package com.tvunetworks.center.user.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.base.Joiner;
import com.tvunetworks.center.common.constant.LocalConstant;
import com.tvunetworks.center.common.constant.UserBehaviorConstant;
import com.tvunetworks.center.common.exception.ClientException;
import com.tvunetworks.center.common.exception.ServerException;
import com.tvunetworks.center.common.model.*;
import com.tvunetworks.center.common.model.dto.grid.AcceptedGrid;
import com.tvunetworks.center.common.model.dto.user.DeviceBelongUserDTO;
import com.tvunetworks.center.common.model.param.AddAndRemoveRPairParam;
import com.tvunetworks.center.common.model.param.AddAndRemoveSourcePairParam;
import com.tvunetworks.center.common.model.param.ListUserPeerIdsParam;
import com.tvunetworks.center.common.model.param.search.SlugInfo;
import com.tvunetworks.center.common.model.vo.AnyWhereVo;
import com.tvunetworks.center.common.model.vo.ChannelUsingCount;
import com.tvunetworks.center.common.util.*;
import com.tvunetworks.center.gs.model.BatteryInfo;
import com.tvunetworks.center.gs.model.Device;
import com.tvunetworks.center.gs.model.DeviceExtend;
import com.tvunetworks.center.gs.model.TokenRequest;
import com.tvunetworks.center.user.config.cache.CacheConfiguration;
import com.tvunetworks.center.user.constant.TokenConstant;
import com.tvunetworks.center.user.constant.UserConstant;
import com.tvunetworks.center.user.mapper.*;
import com.tvunetworks.center.user.model.User;
import com.tvunetworks.center.user.model.*;
import com.tvunetworks.center.user.model.dto.DevicePairDTO;
import com.tvunetworks.center.user.model.dto.DevicePairData;
import com.tvunetworks.center.user.model.json.RExtRelation;
import com.tvunetworks.center.user.model.json.VoBookmark;
import com.tvunetworks.center.user.model.json.VoDevice;
import com.tvunetworks.center.user.model.param.*;
import com.tvunetworks.center.user.model.result.ResultConstant;
import com.tvunetworks.center.user.model.vo.*;
import com.tvunetworks.center.user.service.*;
import com.tvunetworks.center.user.service.feign.*;
import com.tvunetworks.center.user.util.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;

/**
 * @program: tvucc-user
 * @description: UserDeviceServiceImpl
 * @author lebronchen
 * @create: 2019-03-14 11:48
 **/
@Service
@Slf4j
public class UserDeviceServiceImpl implements UserDeviceService {


    @Autowired
    private  UserDeviceService userDeviceService;
    @Autowired
    private  UserBookmarkMapper userBookmarkMapper;
    @Autowired
    private BookmarkDeviceService bookmarkDeviceService;
    @Autowired
    private BookmarkDeviceMapper bookmarkDeviceMapper;
    @Autowired
    private UserDeviceMapper userDeviceMapper;
    @Autowired
    private NewTpcFeignService newTpcFeignService;
    @Autowired
    private DeviceFeignService deviceFeignService;
    @Autowired
    private GcsManageFeignService gcsManageFeignService;
    @Autowired
    private UserHttpService userHttpService;
    @Autowired
    private TokenFeignService tokenFeignService;
    @Autowired
    private TokenRequestMapper tokenRequestMapper;
    @Autowired
    private GridServerService gridServerService;

    @Autowired
    private GridService gridService;

    @Autowired
    private DeviceGeoMapper deviceGeoMapper;

    @Autowired
    private TokenService tokenService;
    @Autowired
    private UserService userService;
    @Autowired
    private UserBehaviorService userBehaviorService;
    @Autowired
    private CustomizedUserDeviceGroupService customizedUserDeviceGroupService;
    @Autowired
    private CustomizedUserGroupService customizedUserGroupService;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    @Qualifier("rListCacheManager")
    private Cache<String, Object> rListCacheManager;
    @Autowired
    private TvuSalesforceFeignService tvuSalesforceFeignService;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    UserDeviceOperationMapper userDeviceOperationMapper;
    @Autowired
    private DeviceService deviceService;
    @Autowired
    private CustomizedDeviceFeignService customizedDeviceFeignService;
    @Autowired
    private AccessServerUtil accessServerUtil;
    @Autowired
    private UserFeatureService userFeatureService;
    @Autowired
    private RoleUserService roleUserService;
    @Autowired
    private RoleManagementService roleManagementService;

    @Value("${execute.notifyDevicePairChange:true}")
    private boolean executeNotifyDevicePairChange;
    @Value("${memcache.key.userCacheRPeerId}")
    private String userCacheRPeerId;
    @Value("${memcache.key.batteryForSource}")
    private String batteryForSource;
    @Value("${ext.type}")
    private String extType;
    @Value("${gridPack}")
    private String gridPack;
    @Value("${gridSdi}")
    private String gridSdi;
    @Value("${tpc.url}")
    private String tpcUrl;
    @Value("${defaultLivePeerName}")
    private String defaultLivePeerName;
    @Value("${redisKey.cacheUserGridToken}")
    private String cacheUserGridTokenKey;
    @Value("${redisTTL.cacheUserGridToken}")
    private long cacheUserGridTokenTime;
    @Value("${redisTTL.cacheUserDevice}")
    private long cacheUserDeviceTime;
    @Value("${alertDeviceChangeTypes}")
    private String alertDeviceChangeTypes;
    @Value("${enableCustomizedCC}")
    private boolean enableCustomizedCC;
    @Value("${gridmarket.url}")
    private String gridmarketUrl;
    @Value("${deviceCope.size}")
    private int deviceCopeSize;
    @Value("${correlateUserDevice.enable.r.relation:true}")
    private boolean correlateUserDeviceEnableRRelation;
    @Value("${correlateUserDevice.enable.r.relation.t:true}")
    private boolean correlateUserDeviceEnableRRelationT;
    @Value("${correlateUserDevice.enable.r.relation.x:true}")
    private boolean correlateUserDeviceEnableRRelationX;

    // 不同设备类型分组的total 缓存时间
    @Value("${redisKey.groupTotalNumber}")
    private String cacheGroupTotal;
    @Value("${redisTTL.groupTotalNumber}")
    private long cacheGroupTotalTtl;

    @Value("${correlateUserDeviceDisableSource}")
    private boolean correlateUserDeviceDisableSource;
    @Value("${DisableReceiverCentric.feature:DisableReceiverCentric}")
    private String disableReceiverCentricFeature;
    @Value("${GlobalGridFeature:GlobalGrid}")
    private String globalGridFeature;
    @Value("${pushLiveUrl}")
    private String pushLiveUrl;
    @Autowired
    private UserBookmarkService userBookmarkService;

    @Autowired
    private DistributedGlobalIdUtil distributedGlobalIdUtil;
    @Autowired
    private UserDeviceRecordService userDeviceRecordService;
    @Autowired
    private TvuSearchFeignService tvuSearchFeignService;

    @Override
    public List<Device> listReceiverControlR(String userId, SearchDeviceParam param) {
        param.setReceiver(true);
        List<Device> devices = this.listUserSourceDevices(userId, param);
        sortDevices(devices, param);
        return devices;
    }

    @Override
    public ListRResult listReceiverControlRAndLastUsed(String userId, SearchDeviceParam param) {
        return listReceiverControlRAndLastUsed(userId, param, UserBehaviorConstant.Remark.R_PAIR_SOURCE);
    }


    @Override
    public ListRResult listReceiverControlRAndLastUsed(String userId, SearchDeviceParam param, String remark) {
        ListRResult listRResult = new ListRResult();

        List<Device> devices = listReceiverControlR(userId, param);

        // set lastUsed and exist
        processLastUsedR(listRResult, devices, userId, remark);

        listRResult.setResult(devices);

        return listRResult;


    }

    @Override
    public PageInfo<Device> pageR(String userId, SearchDeviceParam param) {
        List<Device> devices = listReceiverControlR(userId, param);
        sortDevices(devices, param);
        PageInfo<Device> pageInfo = new PageInfo<>();
        pageInfo.setPageNum(param.getPageNum());
        pageInfo.setPageSize(param.getPageSize());
        PageInfo<Device> devicePageInfo = packagePageInfo(devices, pageInfo);
        return devicePageInfo;
    }


    /**
     * 获取用户R的列表，并把上一次使用的R放在第一个
     *
     * @param listRResult
     * @param devices
     * @param userId
     */
    private void processLastUsedR(ListRResult listRResult, List<Device> devices, String userId, String remark) {


        UserBehavior userBehaviorParam = new UserBehavior()
                .setUserId(userId)
                .setPn(UserBehaviorConstant.Pn.ADVANCE_CONTROL)
                .setServerName(UserBehaviorConstant.ServerName.USER)
                .setRemark(remark);

        Result<String> result = userBehaviorService.getUserBehavior(userBehaviorParam);

        if (!ResultUtil.SUCCESS.equals(result.getErrorCode())) {
            return;
        }

        String content = result.getResult();
        if (StringUtils.isEmpty(content)) {
            return;
        }

        SearchDeviceParam lastSearchParam = null;
        try {
            lastSearchParam = JsonUtil.toObject(content, SearchDeviceParam.class);
        } catch (IOException e) {
            lastSearchParam = new SearchDeviceParam();
            log.error("listR search condition convert to map exception user [{}]", userId, e);
        }

        String rId = lastSearchParam.getRid();

        if (StringUtils.isEmpty(rId)) {
            log.info("listR user behavior is null, user id [{}] lastUse will null", userId);
            return;
        }

        if (StringUtils.isNotBlank(rId)) {
            listRResult.setLastUse(rId)
                    .setExist(true);
        }

        if (CollectionUtils.isEmpty(devices)) {
            return;
        }

        // 需要移动到头部的 device 信息
        Device moveDevice = null;

        for (int i = 0; i < devices.size(); i++) {
            Device device = devices.get(i);
            if (rId.equalsIgnoreCase(device.getPeerId())) {
                moveDevice = device;
                devices.remove(i);
                break;
            }
        }

        if (moveDevice != null) {
            // 如果查找的列表中有上次使用R，则吧这个R放在第一个位置上
            devices.add(0, moveDevice);
        }

    }

    @Override
    public List<Device> listMySource(String userId, SearchDeviceParam param) {

        List<Device> devices = listUserSourceDevices(userId, param);
        sortDevices(devices, param);
        return devices;
    }

    @Override
    public List<Device> listReceiverControlSource(String userId, SearchDeviceParam param) {
        // 根据书签等条件搜索的结果
        List<Device> devices = this.listUserSourceDevices(userId, param);
        sortDevices(devices, param);
        return devices;
    }


    /**
     * 调用 device 服务的接口查询设备的信息
     *
     * @param ids 各种设备的id
     * @return
     */
    private List<Device> listCurrentDevice(Collection<String> ids) {
        if (ids == null || ids.size() == 0) {
            return new ArrayList<>();
        }
        List<Device> devices = deviceService.listCurrentDevice(ids);
        if (devices == null || devices.size() == 0) {
            return new ArrayList<>(0);
        }
        return devices;
    }

    @Override
    public PageInfo<Device> pageReceiverControlSource(String userId, SearchDeviceParam param) {
        List<Device> devices = this.listReceiverControlSource(userId, param);
        PageInfo<Device> pageInfo = new PageInfo<>();
        pageInfo.setPageNum(param.getPageNum());
        pageInfo.setPageSize(param.getPageSize());
        return packagePageInfo(devices, pageInfo);
    }

    @Override
    public PageInfo<Device> pageMySource(String userId, SearchDeviceParam param) {
        List<Device> devices = this.listMySource(userId, param);
        //onGoingEvent filter
        if(param.isOnGoingEvent()){
            devices=filterOngGoingEventDevice(devices);
        }
        PageInfo<Device> pageInfo = new PageInfo<>();
        pageInfo.setPageNum(param.getPageNum());
        pageInfo.setPageSize(param.getPageSize());

        PageInfo<Device> devicePageInfo = packagePageInfo(devices, pageInfo);

        List<Device> resultList = devicePageInfo.getList();

        // 拿到最终要展示的数据，才去查电池信息
        if (param.isBattery()) {
            try {
                if (resultList != null && resultList.size() > 0) {
                    for (Device device : resultList) {
                        // 只要不是offline就去拿电池信息
                        if (!LocalConstant.DeviceStatus.OFFLINE.equals(device.getStatus())) {
//                            device.setBatteryInfo((BatteryInfo) ccMemcacheClient.get(batteryForSource + device.getPeerId().toLowerCase()));

                            //改改为从redis中获取battery信息
                            String batteryInfoStr = deviceFeignService.queryBatteryById(device.getPeerId().toLowerCase());
                            if (StringUtils.isNotEmpty(batteryInfoStr)) {
                                BatteryInfo batteryInfo = JsonUtil.toObject(batteryInfoStr, BatteryInfo.class);
                                device.setBatteryInfo(batteryInfo);
                            }
                        }
                    }
                }
            } catch (Exception e) {
                log.error("Get batteryInfo, memcached key [{}] exception", batteryForSource, e);
            }
        }

        // bookmark 信息
        if (param.isBookmarks()) {
            try {
                if (resultList != null && resultList.size() > 0) {

                    // 提取设备的ID
                    List<String> collect = resultList.stream().map(Device::getPeerId).collect(Collectors.toList());
                    // 查询设备对应的bookmarks
                    //Map<peerIds, bookmarks>
                    Map<String, List<String>> stringListMap = bookmarkDeviceService.listUserDeviceBookmarks(userId, collect);
//                    List<UserBookmarkVo>  list = userBookmarkService.getAllParentBookmarkTree(userId)
                    for (Device device : resultList) {
                        device.setBookmarks(stringListMap.get(device.getPeerId()));
                    }
                }
            } catch (Exception e) {
                log.error("Get batteryInfo, memcached key [{}] exception", batteryForSource, e);
            }
        }
        String parentId = userBookmarkMapper.selectParentId(userId);
        //userDeviceBookmark信息
        if (param.isBookmarkDevice()) {
            if (resultList != null && resultList.size() > 0) {

                if (StringUtils.isEmpty(parentId)) {
                    for (Device device : resultList) {
                        List<BookmarkDevice> bookmarkDeviceList = bookmarkDeviceService.listUserDeviceBookmarksByPeerId(userId, device.getPeerId());

                        if (bookmarkDeviceList == null || bookmarkDeviceList.size() == 0) {
                            continue;
                        }
                        Map userBookrmarkMap = new HashMap();
                        for (BookmarkDevice bookmarkDevice : bookmarkDeviceList) {
                            List<UserBookmarkVo> userBookmarkVoList = userBookmarkService.getAllParentBookmarkTree(userId, bookmarkDevice.getBookmarkId());
                            if (userBookmarkVoList == null) {
                                continue;
                            }
                            userBookrmarkMap.put(bookmarkDevice.getBookmarkId(), userBookmarkVoList);
                        }
                        if (userBookrmarkMap.size() > 0) {
                            device.setUserBookmarkDevice(userBookrmarkMap);
                        }
                    }
                }else {
                    for (Device device : resultList) {
                        List<BookmarkDevice> bookmarkDeviceList = bookmarkDeviceService.listUserDeviceBookmarksByPeerId(userId, device.getPeerId());
                        List<BookmarkDevice> parentBookmarkDeviceList = bookmarkDeviceService.listUserDeviceBookmarksByPeerId(parentId, device.getPeerId());
                        if (CollectionUtils.isEmpty(bookmarkDeviceList) && CollectionUtils.isEmpty(parentBookmarkDeviceList)) {
                            continue;
                        }
                        Map userBookrmarkMap = new HashMap();
                        Map parentBookrmarkMap = new HashMap();
                        if (!CollectionUtils.isEmpty(bookmarkDeviceList)) {
                            for (BookmarkDevice bookmarkDevice : bookmarkDeviceList) {
                                List<UserBookmarkVo> userBookmarkVoList = userBookmarkService.getAllParentBookmarkTree(userId, bookmarkDevice.getBookmarkId());
                                if (userBookmarkVoList == null) {
                                    continue;
                                }
                                userBookrmarkMap.put(bookmarkDevice.getBookmarkId(), userBookmarkVoList);
                            }
                        }
                        if (!CollectionUtils.isEmpty(parentBookmarkDeviceList)) {
                            for (BookmarkDevice parentBookmarkDevice : parentBookmarkDeviceList) {
                                List<UserBookmarkVo> parentBookmarkVoList = userBookmarkService.getAllParentBookmarkTree(parentId, parentBookmarkDevice.getBookmarkId());
                                if (parentBookmarkVoList == null) {
                                    continue;
                                }
                                parentBookrmarkMap.put(parentBookmarkDevice.getBookmarkId(), parentBookmarkVoList);
                            }
                        }
                        if (userBookrmarkMap.size() > 0) {
                            device.setUserBookmarkDevice(userBookrmarkMap);
                        }
                        if (parentBookrmarkMap.size() > 0) {
                            device.setParentBookmarkDevice(parentBookrmarkMap);
                        }
                    }

                }

            }

        }

        // 如果是 token 配对的grid 还要展示配对的状态
        if (param.isGridViaToken()) {
            setGridTokenStatus(userId, resultList);
        }

        // 需求：当 source 正在live的R不是当前 用户下的R，则将live状态改为online
        // 目前已知问题是此结果显示为 online 但却是用living状态搜索出来的
        if (param.isLiving()) {
            setSourceLivePeerInfoForUser(userId, resultList, true, true);
        }

        return devicePageInfo;
    }

    private List<Device> filterOngGoingEventDevice(List<Device> devices) {
        if(CollectionUtils.isEmpty(devices)){
            return devices;
        }
        List<String> peerIds = devices.stream().map(e -> e.getPeerId()).collect(Collectors.toList());

        try {
            List<SlugInfo> slugInfos = tvuSearchFeignService.newestSlugInfo(peerIds);
            long flagTime = System.currentTimeMillis();
            List<String> targetIds = slugInfos.stream().filter(e -> !Objects.equals(e.getDeleteFlag(), 1) &&
                    (Objects.isNull(e.getEndTime()) || e.getEndTime() > flagTime)).map(SlugInfo::getPeerId).collect(Collectors.toList());
            devices=devices.stream().filter(e->targetIds.contains(e.getPeerId())).collect(Collectors.toList());

        } catch (Exception e) {
            log.error("search service error:{}",e.getMessage(),e);
        }
        return devices;
    }

    @Override
    public PageInfo<ExtVo> pageUserExt(PageExtParam param) {
        if (!param.isExt() && !param.isYoutube() && !param.isSmpte2022()) {
            return new PageInfo<>(new ArrayList<>());
        }

        String condition = param.getCondition();
        condition = MyUtil.formatCondition(condition);
        param.setCondition(condition);

        String userId = param.getUserId();
        SearchDeviceParam searchDeviceParam = new SearchDeviceParam()
                .setReceiver(false)
                .setPack(false)
                .setAnywhere(false)
                .setGridPack(false)
                .setGridSdi(false)
                .setExt(true)
                .setLiving(true)
                .setOnline(true)
                .setOffline(true)
                .setNoCamera(true)
                .setBookmardIds(param.getBookmardIds())
                .setUnClassified(param.isUnClassified());
        List<String> allExtIds = this.listUserSourceIds(userId, searchDeviceParam);
        if (CollectionUtils.isEmpty(allExtIds)) {
            return new PageInfo<>(new ArrayList<>());
        }
        List<String> extIds = userDeviceMapper.listUserExtIds(param.getUserId(), param.getCondition(), param.isExt(), param.isYoutube(), param.isSmpte2022());
        if (CollectionUtils.isEmpty(extIds)) {
            PageHelper.startPage(param.getPageNum(), param.getPageSize());
            return new PageInfo<>(new ArrayList<>());
        }
        allExtIds.retainAll(extIds);
        if (CollectionUtils.isEmpty(allExtIds)) {
            PageHelper.startPage(param.getPageNum(), param.getPageSize());
            return new PageInfo<>(new ArrayList<>());
        }
        PageHelper.startPage(param.getPageNum(), param.getPageSize());
        List<ExtVo> list = userDeviceMapper.listExtVo(allExtIds);

        if (!CollectionUtils.isEmpty(list)) {
            try {
                if (list != null && list.size() > 0) {

                    // 提取设备的ID
                    List<String> collect = list.stream().map(ExtVo::getPeerId).collect(Collectors.toList());
                    // 查询设备对应的bookmarks
                    //Map<peerIds, bookmarks>
                    Map<String, List<String>> stringListMap = bookmarkDeviceService.listUserDeviceBookmarks(userId, collect);
                    for (ExtVo device : list) {
                        device.setBookmarks(stringListMap.get(device.getPeerId()));
                    }
                }
            } catch (Exception e) {
                log.error("Get batteryInfo, memcached key [{}] exception", batteryForSource, e);
            }
        }

        return new PageInfo<>(list);
    }

    @Override
    @Transactional
    public void removeUserDevice(String peerId) {
        UserDevice record = new UserDevice().setPeerId(peerId);
        List<UserDevice> existList = userDeviceMapper.select(record);
        if (CollectionUtils.isEmpty(existList)) {
            return;
        }
        for (UserDevice userDevice : existList) {
            userDeviceMapper.delete(userDevice);
        }
    }

    @Override
    public void removeDevivecBindUser(String userIdArr, String peerId) throws Exception {
        this.removeDevivecBindUser(userIdArr, peerId, false);
    }

    @Override
    public void removeDevivecBindUser(String userIdArr, String peerId, boolean relateSource) throws Exception {
        String[] userIdList = userIdArr.split(",");
        List<String> userList = new ArrayList<String>();
        for (int i = 0; i < userIdList.length; i++) {
            userList.add(userIdList[i]);
        }
        userDeviceMapper.removeDevivecBindUser(userList, peerId);

        List<String> peerIds = new ArrayList<>();
        peerIds.add(peerId);

        for (String userId : userList) {

            Set<String> rids = new HashSet<>();
            rids.add(peerId);

            // 移除 R 和 Ext 的关系
            this.removeUserRExtRelation(userId, rids);

            // 移除 R token 配对关系
            this.removeReceiverTokenPair(userId, peerIds);

            if (relateSource) {
                this.removeRPairedTXToUser(userId, rids);
            }

            this.removeUserCacheDevice(userId);
        }

    }

    @Override
    public int addDeviceBindUser(String userId, String peerId, boolean relateSource) throws Exception {
        List<UserDevice> list = checkUserBindWithDevice(userId, peerId);
        if (list == null || list.size() == 0) {
            UserDevice ud = new UserDevice()
                    .setUserId(userId)
                    .setPeerId(peerId)
                    .setRelation(0)
                    .setPostion(0)
                    .setFlag(0)
                    .setId(MyUtil.getUUID());

            userDeviceMapper.insert(ud);

            Set<String> rids = new HashSet<>();
            rids.add(peerId);
            if (relateSource) {
                this.addRPairedTXToUser(userId, rids);
            }

            this.removeUserCacheDevice(userId);
            return 0; //表示未存在绑定
        } else {
            return 1;// 表示已经绑定
        }
    }

    @Override
    public List<String> listUserDevice(String userId, String condition, String types) {
        List<String> peerIdList ;
        condition = MyUtil.formatCondition(condition);
        if (StringUtils.isEmpty(condition) && StringUtils.isEmpty(types)) {
            peerIdList = listUserCacheDeviceIds(userId);
        } else {
            peerIdList = userDeviceMapper.listUserDevice(userId, condition, types);
        }
        return peerIdList;
    }


    /**
     * [My Source]
     * <p>
     * 此方法会先过滤出来正在live的 Source ,然后再修正状态
     * 是否修正状态要看 这个 Source 正在 live 的 R 是否是当前账户下的 R
     *
     * @param userId          用户的 ID
     * @param allDevice       所有的设备
     * @param setStatus       是否修正状态
     * @param setLivePeerInfo 是否修正 live peer info
     * @return 状态是否被修正。 true 为修正，false 反之
     */
    private boolean setSourceLivePeerInfoForUser(String userId, Collection<Device> allDevice, boolean setStatus, boolean setLivePeerInfo) {

        boolean modify = false;

        if (!setStatus && !setLivePeerInfo) {
            return modify;
        }

        if (allDevice == null || allDevice.size() == 0) {
            return modify;
        }

        // 在这里直接查出用户下的R，不用多次读取 memcache
        List<String> rIds = listCacheRPeerId(userId);

        for (Device device : allDevice) {
            boolean isStatus = false;
            if ("83cca10aa0972b150000000000000002".equals(device.getPeerId().toLowerCase())) {
                log.error("rIds from cache===" + JSONObject.toJSONString(rIds));
                isStatus = true;
            }
            // 不修正 R 和 T
            if (!StringUtils.equals(LocalConstant.DeviceType.R, device.getType())
                    && LocalConstant.DeviceStatus.LIVING.equals(device.getStatus())) {

                // Get live peer info
                String livePeerIds = device.getLivePeerId();
                String livePeerNames = device.getLivePeerName();
                if (isStatus) {
                    log.error("livePeerIds=" + livePeerIds);
                }
                if (StringUtils.isBlank(livePeerIds) || StringUtils.isBlank(livePeerNames)) {
                    continue;
                }

                // 如果是 T 则直接使 gridLivePeerId 和 livePeerId 保持一致
                // gridLivePeerName 和 livePeerName 保持一致
                if (StringUtils.equals(LocalConstant.DeviceType.T, device.getType())) {
                    device.setGridLivePeerId(device.getLivePeerId());
                    device.setGridLivePeerName(device.getLivePeerName());
                    continue;
                }

                List<String> livePeerIdList = Arrays.asList(livePeerIds.split(";"));
                List<String> livePeerNameList = Arrays.asList(livePeerNames.split(";"));
                if (isStatus) {
                    log.error("livePeerIdList====" + JSONObject.toJSONString(livePeerIdList));
                }
                // 这里重写一下 retainAll 方法，因为不只是要过滤receiver id 还要 receiver 的 name
//                        livePeerIdList.retainAll(rIds);

                List<Device> liveDevices = new ArrayList<>();

                // 查出来 source 可用的 R 中包含 live peer id 才 add 到 liveDevices 中
                // 这里的 R 一定是这个账户下的 R 才显示
                for (int i = 0; i < livePeerIdList.size(); i++) {
                    if (rIds.contains(livePeerIdList.get(i))) {
                        Device liveDevice = new Device();
                        liveDevice.setLivePeerId(livePeerIdList.get(i));
                        liveDevice.setLivePeerName(livePeerNameList.get(i));
                        liveDevices.add(liveDevice);
                    }
                }
                if (isStatus) {
                    log.error("liveDevices====" + JSONObject.toJSONString(liveDevices));
                }
                // 如果 source 正在live的R中没有一个是当前用户下的则将状态改为 online
                if (setStatus && liveDevices.size() == 0) {
                    device.setStatus(LocalConstant.DeviceStatus.ONLINE);
                    device.setLivePeerId("").setLivePeerName("");
                    modify = true;
                } else if (setLivePeerInfo && liveDevices.size() > 0) {
                    // 如果当前 source live的R中有当前账户的R，则LivePeerId 只显示当前账户的R下的R，前端只显示第一个RId

                    //存放第一个device
                    device.setLivePeerId(liveDevices.get(0).getLivePeerId());
                    device.setLivePeerName(liveDevices.get(0).getLivePeerName());

                    String allLivePeerId = liveDevices
                            .stream()
                            .map(Device::getLivePeerId)
                            .collect(Collectors.joining(";"));
                    String allLivePeerName = liveDevices
                            .stream()
                            .map(Device::getLivePeerName)
                            .collect(Collectors.joining(";"));

                    device.setGridLivePeerId(allLivePeerId);
                    device.setGridLivePeerName(allLivePeerName);


                }

            }
        }
        return modify;
    }


    /**
     * [Advance Control] 只修改 grid 状态
     * <p>
     * 此方法会先过滤出来正在live的 Grid ,然后再修正状态
     * 是否修正状态要看 Grid live R 是否是当前的 R
     *
     * @param receiverId      R 的 ID
     * @param allDevice       所有的设备
     * @param setStatus       是否修正状态
     * @param setLivePeerInfo 是否修正 live peer info
     * @return 状态是否被修正。 true 为修正，false 反之
     */
    private boolean setSourceLivePeerInfoForR(String receiverId, Collection<Device> allDevice, boolean setStatus, boolean setLivePeerInfo) {

        boolean modify = false;

        if (!setStatus && !setLivePeerInfo) {
            return modify;
        }

        if (allDevice == null || allDevice.size() == 0) {
            return modify;
        }

        for (Device device : allDevice) {
            // 正在 live 的 source
            if (StringUtils.equals(LocalConstant.DeviceType.X, device.getType()) &&
                    StringUtils.equals(LocalConstant.DeviceStatus.LIVING, device.getStatus())) {

                // Get live peer info
                String livePeerIds = device.getLivePeerId();
                String livePeerNames = device.getLivePeerName();

                if (StringUtils.isBlank(livePeerIds)) {
                    continue;
                }

                List<String> livePeerIdList = Arrays.asList(livePeerIds.split(";"));
                List<String> livePeerNameList = Arrays.asList(livePeerNames.split(";"));


                // 如果当前的 grid 正在和当前的 R live
                // finalLivePeerId和finalLivePeerName分别指当前 R 的id 和 name
                String finalLivePeerId = "";
                String finalLivePeerName = "";

                // 查出来 grid 可用的 R 中包含 live peer id才 add 到 liveDevices 中
                for (int i = 0; i < livePeerIdList.size(); i++) {

                    if (StringUtils.equalsIgnoreCase(livePeerIdList.get(i), receiverId)) {
                        finalLivePeerId = livePeerIdList.get(i);
                        finalLivePeerName = livePeerNameList.get(i);
                        break;
                    }
                }

                // 如果 grid 正在live的R中没有一个是 当前的 R 的则将状态改为 online
                if (setStatus && StringUtils.isBlank(finalLivePeerId)) {
                    device.setStatus(LocalConstant.DeviceStatus.ONLINE);
                    device.setLivePeerId("")
                            .setLivePeerName("");
                    modify = true;
                } else if (setLivePeerInfo && StringUtils.isNotBlank(finalLivePeerId)) {
                    //存放第一个device
                    device.setLivePeerId(finalLivePeerId);
                    device.setLivePeerName(finalLivePeerName);
                }
            }
        }
        return modify;
    }

    private void sortDevices(List<Device> devices, SearchDeviceParam param) {

        if (devices == null || devices.size() == 0) {
            return;
        }

        try {
            String s = MyUtil.MAPPER.writeValueAsString(devices);
            log.info(s);
        } catch (JsonProcessingException e) {
            log.error("Exception: ", e);
        }
        Comparator<Device> comparator = null;
        if (param.isOnlineFirst()) {
            comparator = new DeviceCompareOnlineFirst();
        } else if (param.isLiveFirst()) {
            comparator = new DeviceCompareLiveFirst();
        } else {
            comparator = new DeviceCompareByName();
        }
        try {
            Collections.sort(devices, comparator);
        } catch (Exception e) {
            log.error("sortDevices11111>>>>>devices:[{}],exception:[{}]", devices, e);
        }
    }

    private <T> PageInfo<T> packagePageInfo(List<T> list, PageInfo<T> pageInfo) {
        Page<T> page = new Page<>();

        if (list == null || list.size() == 0) {
            list = new ArrayList<>();
        }

        page.setPageNum(pageInfo.getPageNum())
                .setPageSize(pageInfo.getPageSize())
                .setTotal(list.size());
        page.addAll(subPageList(list, pageInfo));


        return new PageInfo<>(page, 8);

    }

    /**
     *
     * @param vs vs
     * @param pb pb
     * @param <T> t
     * @return t
     */
    protected <T> List<T> subPageList(List<T> vs, PageInfo<T> pb) {
        int pageIndex = pb.getPageNum();
        if (pageIndex < 1) {
            pageIndex = 1;
        }
        pb.setPageNum(pageIndex);
        if (vs.size() > 0 && ((pageIndex - 1) * pb.getPageSize()) < Math.min(pageIndex * pb.getPageSize(), vs.size())) {
            return vs.subList(((pageIndex - 1) * pb.getPageSize()),
                    Math.min(pageIndex * pb.getPageSize(), vs.size()));
        } else {
            return new ArrayList<>();
        }
    }

    /**
     *
     * @param vs vs
     * @param pb pb
     * @param <V> v
     * @param <T> t
     * @return t
     */
    protected <V, T> int getPages(List<V> vs, PageInfo<T> pb) {
        if (vs == null || vs.size() == 0) {
            return 0;
        }

        if (vs.size() % pb.getPageSize() == 0) {
            return vs.size() / pb.getPageSize();
        } else {
            return vs.size() / pb.getPageSize() + 1;
        }
    }

//    @Override
//    public List<String> listUserPeerIds(String userId, String rid, SearchDeviceParam param) {
//        List<String> bookmarkPeerIds = bookmarkDeviceService.listUserPeerIdFilterByBookmarkAndCondition(userId, param);
//        if (bookmarkPeerIds == null) {
//            bookmarkPeerIds = new ArrayList<>();
//        }
//        List<String> typePeerIds = this.listUserPeerIdFilterByTypeAndCondition(userId, param);
//        if (typePeerIds == null) {
//            typePeerIds = new ArrayList<>(0);
//        }
//
//        if (StringUtils.isNotBlank(rid)) {
//            List<String> bindPeerIds = new ArrayList<>();
//            if (param.isPack() || param.isAnywhere()) {
//                List<String> tids = deviceFeignService.listRPairT(rid);
//                if (tids != null && tids.size() > 0) {
//                    bindPeerIds.addAll(tids);
//                }
//            }
//            if (param.isGridPack() || param.isGridSdi()) {
//                List<String> xids = deviceFeignService.listRPairX(rid);
//                if (xids != null && xids.size() > 0) {
//                    bindPeerIds.addAll(xids);
//                }
//            }
//            if (param.isExt()) {
//                String types = UserUtil.packageExtTypesToString(extType);
//                List<String> extPeerIds = userDeviceMapper.listUserExt(userId, param.getCondition(), types);
//                if (extPeerIds != null && extPeerIds.size() > 0) {
//                    bindPeerIds.addAll(extPeerIds);
//                }
//            }
//            typePeerIds.retainAll(bindPeerIds);
//        }
//
//        bookmarkPeerIds.retainAll(typePeerIds);
//
//        // 根据需求，如果 token 和 anywhere 都勾选则只查 token 配对的 anywhere，不能是当前用户下的anywhere，所以需要做排除
//        if (param.isAnywhere() && param.isToken()) {
//            List<String> tokenAnywhereIds = getTokenAnywhereIds(userId, param.getCondition());
//            bookmarkPeerIds.addAll(tokenAnywhereIds);
//        }
//
//
//        Set<String> resultSet = new HashSet<>(bookmarkPeerIds);
//
//        // Query R source
//        if (param.isAllStatusByR()) {
//            return new ArrayList<>(resultSet);
//        }
//        List<String> resultList = new ArrayList<>();
//        Map<String, Device> deviceMap = deviceFeignService.mapCurrentDevice(new ListDeviceParam(resultSet));
//        for (String peerId : resultSet) {
//            String status = "0";
//            Device device = deviceMap.get(peerId);
//            if (device != null) {
//                status = device.getStatus();
//            }
//            boolean statusExist = param.isStatusExistByR(status);
//            if (statusExist) {
//                resultList.add(peerId);
//            }
//        }
//
//        return resultList;
//    }

    @Override
    public List<String> listUserSourceIds(String userId, SearchDeviceParam param) {
        List<Device> devices = listUserSourceDevices(userId, param);

        if (CollectionUtils.isEmpty(devices)) {
            return new ArrayList<>(0);
        }

        // 提取 device 中的peerId
        return devices.stream().map(Device::getPeerId).collect(Collectors.toList());
    }

    @Override
    public Set<String> listUnfilteredStatusUserSourceIds(String userId, SearchDeviceParam param) {
        // 没有勾选任何的 bookmark
        if (param.isEmptyBookmark()) {
            return new HashSet<>(0);
        }

        //
        // status 举例参数对比
        //              My Source    Advance Control
        // live          false       false
        // online        false       false
        // offline       false       false
        // noCamera      false       x(默认为false)
        //
        // 查询 source 时，什么 type 都没有选择 或者 什么状态也没选择
        // 如果在 My Sources 页面什么过滤也没选，那么对于 Advance Control 页面也是什么都没选，
        // 因为 My Sources 中的选项要多于 Advance Control,所以 这里只判断 My Sources 的过滤情况
        if (param.isNullTypeForMySource() || param.isNullStatusForMySource()) {
            return new HashSet<>(0);
        }
        List<String> bookmarkPeerIdsForToke = new ArrayList<>();
        List<String> bookmarkPeerIds = bookmarkDeviceService.listUserPeerIdFilterByBookmarkAndCondition(userId, param);

        if (bookmarkPeerIds == null) {
            bookmarkPeerIds = new ArrayList<>();
        }

        bookmarkPeerIdsForToke.addAll(bookmarkPeerIds);

        List<String> typePeerIds = this.listUserPeerIdFilterByTypeAndCondition(userId, param);
        if (typePeerIds == null) {
            typePeerIds = new ArrayList<>(0);
        }

        bookmarkPeerIds = bookmarkPeerIds.stream().map(String::toLowerCase).collect(Collectors.toList());
        typePeerIds = typePeerIds.stream().map(String::toLowerCase).collect(Collectors.toList());
        bookmarkPeerIds.retainAll(typePeerIds);

        String rid = param.getRid();
        if (StringUtils.isNotBlank(rid)) {
            List<String> bindPeerIds = new ArrayList<>();
            if (param.isPack() || param.isAnywhere()) {
                List<String> tids = deviceFeignService.listRPairT(rid);
                if (tids != null && tids.size() > 0) {
                    bindPeerIds.addAll(tids);
                }
            }
            if (param.isGridPack() || param.isGridSdi()) {
                List<String> xids = deviceFeignService.listRPairX(rid);

                if (xids != null && xids.size() > 0) {
                    bindPeerIds.addAll(xids);
                }
            }
            if (param.isExt()) {
                String types = UserUtil.packageExtTypesToString(extType);
                String condition = param.getCondition();
                condition = MyUtil.formatCondition(condition);
                List<String> extPeerIds = userDeviceMapper.listUserExt(userId, condition, types);
                if (extPeerIds != null && extPeerIds.size() > 0) {
                    bindPeerIds.addAll(extPeerIds);
                }
            }
            bindPeerIds = bindPeerIds.stream().map(String::toLowerCase).collect(Collectors.toList());
            bookmarkPeerIds.retainAll(bindPeerIds);
        }


        // 根据需求，如果 token 和 anywhere 都勾选则只查 token 配对的 anywhere，不能是当前用户下的anywhere，所以需要做排除

        // 因为anywhere 是从listUserPeerIdFilterByTypeAndCondition 查询,所以只要对token 单独做查询即可
        if (param.isAnywhere() && param.isToken()) {
            //if (param.isAnywhere()) {
            List<String> tokenAnywhereIds = getTokenAnywhereIds(userId, rid, param.isTokenRegardlessOfUser(), param.getCondition(), Boolean.FALSE);
            if (bookmarkPeerIdsForToke.size() > 0 && !StringUtils.equalsIgnoreCase("all", param.getBookmardIds())
                    && !CollectionUtils.isEmpty(tokenAnywhereIds)) {
                bookmarkPeerIdsForToke = bookmarkPeerIdsForToke.stream().map(String::toLowerCase).collect(Collectors.toList());
                tokenAnywhereIds = tokenAnywhereIds.stream().map(String::toLowerCase).collect(Collectors.toList());
                for (String id : tokenAnywhereIds) {
                    if (StringUtils.isNotEmpty(param.getBookmardIds()) && bookmarkPeerIdsForToke.contains(id.toLowerCase())) {
                        //如果已经设置书签则显示书签
                        bookmarkPeerIds.add(id);
                    }
                }
                if (param.isUnClassified()) {
                    //所有没有分配到bookmark的anywhere
                    List<String> bookmarkPeerIdList = bookmarkDeviceMapper.listUserInBookmarkPeerIds(userId, param.getCondition());
                    if (!CollectionUtils.isEmpty(bookmarkPeerIdList)) {
                        bookmarkPeerIdList = bookmarkPeerIdList.stream().map(String::toLowerCase).collect(Collectors.toList());
                        tokenAnywhereIds.removeAll(bookmarkPeerIdList);
                    }
                    bookmarkPeerIds.addAll(tokenAnywhereIds);
                }
            } else if (StringUtils.equalsIgnoreCase("all", param.getBookmardIds())) {//否则显示所有
                bookmarkPeerIds.addAll(tokenAnywhereIds);
            }
        }
////


        //当勾选的是token的需要查询根据userId查询token device表的设备信息
        /*if (param.isToken() && param.isUnClassified()) {
            List<SearchUserDeviceVo> queryTokenDeviceList = null;
            try {
                queryTokenDeviceList = userDeviceMapper.queryTokenDeviceList(param.getCondition(), userId);
            } catch (Exception e) {
                log.error(">>>>>>>>>>>listUnfilteredStatusUserSourceIds is error{}", e);
            }
            if (queryTokenDeviceList != null && queryTokenDeviceList.size() > 0) {
                List<String> tokenDeviceIds = new ArrayList<String>();
                //获取设备的id
                for (SearchUserDeviceVo searchUserDeviceVo : queryTokenDeviceList) {
                    if (searchUserDeviceVo == null) {
                        continue;
                    }
                    String peerId = searchUserDeviceVo.getPeerId();
                    if (StringUtils.isEmpty(peerId)) {
                        continue;
                    }
                    tokenDeviceIds.add(peerId);
                }
                if (tokenDeviceIds.size() > 0) {
                    bookmarkPeerIds.addAll(tokenDeviceIds);
                    List<String> retList = new ArrayList<String>();
                    //去除重复
                    bookmarkPeerIds.stream().forEach(
                            p -> {
                                if (!retList.contains(p)) {
                                    retList.add(p);
                                }
                            }
                    );
                    if (retList != null || retList.size() > 0) {
                        bookmarkPeerIds = retList;
                    }
                }
            }
        }*/


        // Query token grid
        if (param.isGridViaToken() && param.isUnClassified()) {
            List<String> gridViaTokenIds = getGridViaTokenIds(userId, param.getCondition());
            List<String> gridSdiList = new ArrayList<>();
            List<String> gridPackList = new ArrayList<>();
            gridViaTokenIds.forEach(s ->{
                if (StringUtils.equals("2",s.substring(s.length()-1,s.length()))){
                    gridSdiList.add(s);
                }else {
                    gridPackList.add(s);
                }
            });
            if (param.isGridPack()){
                bookmarkPeerIds.addAll(gridPackList);
            }else if (param.isGridSdi()){
                bookmarkPeerIds.addAll(gridSdiList);
            }

            if (param.isGridPack() &&  param.isGridSdi()){
                bookmarkPeerIds.addAll(gridPackList);
                bookmarkPeerIds.addAll(gridSdiList);
            }
     //       bookmarkPeerIds.addAll(getGridViaTokenIds(userId, param.getCondition()));

        }
        // Query Global Grid
        if (param.isGlobalGrid() && param.isUnClassified()) {
            List<String> globalGridIds = getGlobalGridIdsByUserId(userId, param.getCondition());
            List<String> gridSdiList = new ArrayList<>();
            List<String> gridPackList = new ArrayList<>();
            globalGridIds.forEach(s ->{
                if (StringUtils.equals("2",s.substring(s.length()-1,s.length()))){
                    gridSdiList.add(s);
                }else {
                    gridPackList.add(s);
                }
            });
            if (param.isGridPack()){
                bookmarkPeerIds.addAll(gridPackList);
            }else if (param.isGridSdi()){
                bookmarkPeerIds.addAll(gridSdiList);
            }

            if (param.isGridPack() &&  param.isGridSdi()){
                bookmarkPeerIds.addAll(gridPackList);
                bookmarkPeerIds.addAll(gridSdiList);
            }
        //    bookmarkPeerIds.addAll(getGlobalGridIdsByUserId(userId, param.getCondition()));
        }

        //添加该用户扫码配对的Anywhere
        //因为方法复用太多,担心影响别的逻辑,所以添加一个标识符,当mysource参数为1时,表示是CC的Mysouce界面需要拿数据做展示
        if(param.getMySource()==1){
            List<String> anyWhereByUserId = tokenFeignService.findAnywhere(userId);
            bookmarkPeerIds.addAll(anyWhereByUserId);
        }

        return new HashSet<>(bookmarkPeerIds);
    }

    @Override
    public List<Device> listUserSourceDevices(String userId, SearchDeviceParam param) {
//        System.out.println("==========================================........");

        Set<String> sourceIds = listUnfilteredStatusUserSourceIds(userId, param);
        //
        //  以下方法在获取设备的状态，同时修正 Source 状态
        //

        List<Device> extFromWebR = new ArrayList<>();
        if (param.isSyncWebR() && param.isExt() && StringUtils.isNotEmpty(param.getRid())) {
            extFromWebR = deviceFeignService.getExtFromWebR(param.getRid());
            if (!CollectionUtils.isEmpty(extFromWebR) && StringUtils.isNotEmpty(param.getCondition())) {
                extFromWebR = extFromWebR.stream().filter(s -> StringUtils.containsIgnoreCase(s.getPeerId(), param.getCondition())
                        || StringUtils.containsIgnoreCase(s.getName(), param.getCondition())).collect(Collectors.toList());
            }
        }
        if (CollectionUtils.isEmpty(sourceIds) && CollectionUtils.isEmpty(extFromWebR)) {
            return new ArrayList<>();
        }

//        Map<String, Device> deviceMap = deviceFeignService.mapCurrentDevice(new ListDeviceParam(sourceIds));

        List<Device> devices = CollectionUtils.isEmpty(sourceIds) ? new ArrayList<>() : deviceService.listCurrentDevice(sourceIds);
        if (!CollectionUtils.isEmpty(extFromWebR)) {
            if (CollectionUtils.isEmpty(devices)) {
                devices = extFromWebR;
            }else {
                List<String> extPeerIds = devices.stream().filter(s -> StringUtils.equalsIgnoreCase(s.getType(), "Ext"))
                        .map(s -> s.getPeerId().toLowerCase()).collect(Collectors.toList());
                List<Device> notExistExts = extFromWebR.stream().filter(s -> !extPeerIds.contains(s.getPeerId().toLowerCase())).collect(Collectors.toList());
                devices.addAll(notExistExts);
            }
        }
        Map<String, Device> deviceMap = new HashMap<>();
        for (Device device : devices) {

            //对数据库和缓存状态不一致的device 做过滤校验
            if (param.isOffline() && !param.isOnline() && !param.isLiving()) {
                if (!"1".equals(device.getStatus()) && !"2".equals(device.getStatus())) {
                    deviceMap.put(device.getPeerId(), device);
                }
            } else if (param.isOffline() && param.isOnline() && !param.isLiving()) {
                if (!"2".equals(device.getStatus())) {
                    deviceMap.put(device.getPeerId(), device);
                }
            } else if (param.isOffline() && !param.isOnline() && param.isLiving()) {
                if (!"1".equals(device.getStatus())) {
                    deviceMap.put(device.getPeerId(), device);
                }
            } else {
                deviceMap.put(device.getPeerId(), device);
            }
        }

        List<Device> sourceDevice = new ArrayList<>(deviceMap.values());

        // Query user source
        // rid 是 null 说明 是查用户下的source
        // 否则说明是查 R 下的 source
        if (StringUtils.isBlank(param.getRid())) {
            // 修正 source 状态 [My Source],
            // 因为 set livePeerInfo 工作量很大所以在最终返回给用户的时候再set
            setSourceLivePeerInfoForUser(userId, sourceDevice, true, false);
        } else if (StringUtils.isNotBlank(param.getRid())) {
            // 修正 source 状态 [Advance Control] ,
            // 因为 set livePeerInfo 工作量很少所以直接在这个地方直接set
            setSourceLivePeerInfoForR(param.getRid(), sourceDevice, true, true);
        }

        List<Device> resultList = new ArrayList<>();
        // 过滤状态
        for (Device device : sourceDevice) {
            String status = "0";
            if (device != null) {
                status = device.getStatus();
            }
            if (device != null && StringUtils.isEmpty(status)) {
                log.error("listUserSourceDevices222>>>>>status is empty.device:[{}]", device);
                status = "0";
                device.setStatus("0");
            }
            boolean statusExist;

            if (StringUtils.isBlank(param.getRid())) { // 根据 user 查 source
                statusExist = param.isStatusExistByUser(status);
            } else { // 根据 R 查source
                statusExist = param.isStatusExistByR(status);
            }

            if (statusExist && device != null) {
                resultList.add(device);
            }
        }

        if(param.isAlert()) {
            List<Device> collect = resultList.stream().filter(s ->
                    StringUtils.equals("T",s.getType()) ||    StringUtils.equals("R",s.getType()) ||    StringUtils.equals("X",s.getType())
            ).collect(Collectors.toList());
            return collect;
        }
        return resultList;

    }

    /**
     * 勾选了 token 和 anywhere
     *
     * @param userId userId
     * @param rid rid
     * @param tokenRegardlessOfUser tokenRegardlessOfUser
     * @param excludeFlag excludeFlag
     * @param condition  condition
     * @return List
     */
    public List<String> getTokenAnywhereIds(String userId, String rid, boolean tokenRegardlessOfUser, String condition, boolean excludeFlag) {
        condition = MyUtil.formatCondition(condition);
        if (tokenRegardlessOfUser) {
            // 定制 CC 需求，和用户 R 有配对的所有 T
            List<String> allTids = userDeviceMapper.listUserTokenTidsRegardlessOfUser(userId, rid);
            if (CollectionUtils.isEmpty(allTids)) {
                return new ArrayList<>(0);
            }
            if (StringUtils.isBlank(condition)) {
                return allTids;
            }
            Set<String> allTids2 = userDeviceMapper.filterCondition(new HashSet<>(allTids), condition);
            if (CollectionUtils.isEmpty(allTids2)) {
                return new ArrayList<>(0);
            }
            return new ArrayList<>(allTids2);
        } else {
            // Query this user token paired T
//            List<String> tokenAnywhereIds = userDeviceMapper.listUserTokenTids(userId, condition);
//            List<String> tokenPeerIds = null;
//            if (StringUtils.isBlank(rid)) {
//                tokenPeerIds = userDeviceMapper.listUserTokenTids(userId, condition);
//            } else {
//                try {
//                    tokenPeerIds = tokenFeignService.getRPairTbyRidAndUserId(userId, rid);
//                } catch (Exception e) {
//                    log.error(e.toString(), e);
//                }
//            }
//
            // token 设备不在乎用户
            Set<String> rids = new HashSet<>();
            if (StringUtils.isNotBlank(rid)) {
                rids.add(rid);
            } else {
                rids = new HashSet<>(this.listUserRids(userId));
            }
            Set<String> tokenPeerIds = new HashSet<>();
            if (!CollectionUtils.isEmpty(rids)) {
                tokenPeerIds = tokenFeignService.listRsPairedTids(rids);
            }

            if (CollectionUtils.isEmpty(tokenPeerIds)) {
                return new ArrayList<>();
            }
            if (StringUtils.isNotBlank(condition)) {
                tokenPeerIds = userDeviceMapper.filterCondition(tokenPeerIds, condition);
            }
            if (CollectionUtils.isEmpty(tokenPeerIds)) {
                return new ArrayList<>();
            }
            if (excludeFlag) {
                // Query the T that belong to this user
                List<String> tIds = this.listUserDevice(userId, condition, LocalConstant.DeviceType.T);

                if (tIds == null) {
                    tIds = new ArrayList<>(0);
                }
                // Exclude
                tokenPeerIds.removeAll(tIds);
            }
            return new ArrayList<>(tokenPeerIds);
        }
    }

    @Override
    public Result<String> getRSourceTypeList(String rid) throws Exception {
        return deviceFeignService.getRSourceTypeList(rid);
    }

    private List<String> getGridViaTokenIds(String userId, String condition) {
        condition = MyUtil.formatCondition(condition);
        //尾号是000000002是SDI,尾号是000000000001是Pack
        List<String> gridViaTokenIds = userDeviceMapper.listUserTokenGridIds(userId, condition);

        if (gridViaTokenIds == null) {
            return new ArrayList<>(0);
        }

        return gridViaTokenIds;
    }

    /**
     * 这个方法是根据用户下所有的 R id 去 Grid Server 查询可以用的 Grid
     *
     * @param userId
     * @param condition
     * @return
     */
    private List<String> getGlobalGridIds(String userId, String condition) {
        Set<String> globeGridIds = new HashSet<>();
        List<String> listCacheRPeerIds = listCacheRPeerId(userId);


        // 用逗号拼接
        String rIds = String.join(",", listCacheRPeerIds);

        List<Map<String, String>> res = null;
        try {
            res = gridServerService.getBindXByRids(rIds, condition);
        } catch (Exception e) {
            res = new ArrayList<>();
            log.error("Get Grid getGridSourceByRidForGM Exception", e);
        }

        if (res != null && res.size() > 0) {
            for (Map<String, String> map : res) {
                String deviceId = map.get("device_id");
                String resourceId = map.get("resource_id");
                String isAuto = String.valueOf(map.get("is_auto"));
                String xId = deviceId + resourceId;
                if (isAuto.equals("1")) {
                    globeGridIds.add(xId);
                }
            }
        }

        return new ArrayList<>(globeGridIds);
    }

    /**
     * 直接根据用户的 id 去 Grid 查询 Grid
     *
     * @param userId
     * @param condition
     * @return
     */
    private List<String> getGlobalGridIdsByUserId(String userId, String condition) {
//        Set<String> globeGridIds = new HashSet<>();

        List<AcceptedGrid> res = null;
        try {
            res = gridService.getGridByUserId(userId, condition);
        } catch (Exception e) {
            log.error("Get Grid getGridSourceByRidForGM Exception", e);
            return new ArrayList<>();
        }

        if (CollectionUtils.isEmpty(res)) {
            return new ArrayList<>();
        }

        return res.stream().map(AcceptedGrid::getPeerId).collect(Collectors.toList());
    }


    @Override
    public List<String> listUserPeerIdFilterByTypeAndCondition(String userId, SearchDeviceParam param) {
        if (param.isNullType() || param.isNullTypeForMySource()) {
            return new ArrayList<>();
        }
        String typeCondition = this.packageTypeCondition(param);
        String condition = param.getCondition();
        condition = MyUtil.formatCondition(condition);
        return userDeviceMapper.listUserPeerIdFilterByTypeAndCondition(userId, condition, typeCondition);
    }

    @Override
    public List<String> listUserRids(String userId) {
        return userDeviceMapper.listUserDeviceIds(userId, LocalConstant.DeviceType.R);
    }

    @Override
    public List<String> listUserTids(String userId) {
        return userDeviceMapper.listUserDeviceIds(userId, LocalConstant.DeviceType.T);
    }

    @Override
    public List<String> listUserXids(String userId) {
        return userDeviceMapper.listUserDeviceIds(userId, LocalConstant.DeviceType.X);
    }

    @Override
    public List<String> listUserDeviceIds(String userId) {
        return userDeviceMapper.listUserAllDeviceIds(userId);
    }

    @Override
    public List<String> listUserCacheRids(String userId) {
        List<String> list = redisUtil.get(UserConstant.RedisKey.CACHE_USER_DEVICE + LocalConstant.DeviceType.R + userId, List.class);
        if (list != null) {
            return list;
        }
        list = this.listUserRids(userId);
        redisUtil.set(UserConstant.RedisKey.CACHE_USER_DEVICE + LocalConstant.DeviceType.R + userId, list, cacheUserDeviceTime);
        return list;
    }

    @Override
    public List<String> listUserCacheTids(String userId) {
        List<String> list = redisUtil.get(UserConstant.RedisKey.CACHE_USER_DEVICE + LocalConstant.DeviceType.T + userId, List.class);
        if (list != null) {
            return list;
        }
        list = this.listUserTids(userId);
        redisUtil.set(UserConstant.RedisKey.CACHE_USER_DEVICE + LocalConstant.DeviceType.T + userId, list, cacheUserDeviceTime);
        return list;
    }

    @Override
    public List<String> listUserCacheXids(String userId) {
        List<String> list = redisUtil.get(UserConstant.RedisKey.CACHE_USER_DEVICE + LocalConstant.DeviceType.X + userId, List.class);
        if (list != null) {
            return list;
        }
        list = this.listUserXids(userId);
        redisUtil.set(UserConstant.RedisKey.CACHE_USER_DEVICE + LocalConstant.DeviceType.X + userId, list, cacheUserDeviceTime);
        return list;
    }

    @Override
    public List<String> listUserCacheDeviceIds(String userId) {
        List<String> list = redisUtil.get(UserConstant.RedisKey.CACHE_USER_DEVICE + userId, List.class);
        if (list != null) {
            return list;
        }
        list = this.listUserDeviceIds(userId);
        redisUtil.set(UserConstant.RedisKey.CACHE_USER_DEVICE + userId, list, cacheUserDeviceTime);
        return list;
    }

    @Override
    public List<String> listCacheDeviceBelongUser(String peerId) {
        if (StringUtils.isEmpty(peerId)) {
            return null;
        }
        List<String> list = redisUtil.get(UserConstant.RedisKey.CACHE_USER_DEVICE + peerId, List.class);
        if (list != null) {
            return list;
        }
        list = this.listDeviceBelongUser(peerId);
        redisUtil.set(UserConstant.RedisKey.CACHE_USER_DEVICE + peerId, list, cacheUserDeviceTime);
        return list;
    }

    private List<String> listDeviceBelongUser(String peerId) {
        List<String> allUserIds = userDeviceMapper.listDeviceBelongUser(peerId);

        // 如果是 Anywhere，那么去 tvucc-token 查询 Token 配对了这个 anywhere 的用户
        Device device = deviceService.getCurrentDevice(peerId);
        if (device != null && LocalConstant.DeviceType.T.equals(device.getType())) {
            String platform = device.getPlatform();
            if (StringUtils.isNotEmpty(platform)) {
                int plat = Integer.parseInt(platform.trim());
                if (plat >= 10 && plat <= 14) {
                    Set<String> pairTokenUserIds = tokenFeignService.listCCOwnTokenAnywhereUsers(peerId);
                    if (!CollectionUtils.isEmpty(pairTokenUserIds)) {
                        allUserIds.addAll(pairTokenUserIds);
                    }
                }
            }
        }
        if (CollectionUtils.isEmpty(allUserIds)) {
            return new ArrayList<>();
        }
        allUserIds = allUserIds.stream().distinct().collect(Collectors.toList());
        return allUserIds;
    }


    /**
     * UserDevice 发生变化的时候调用这个接口 清除 Redis 缓存
     *
     * @param userId
     */
    private void removeUserCacheDevice(String userId) {
        redisUtil.delete(UserConstant.RedisKey.CACHE_USER_DEVICE + userId);
//        redisUtil.delete(UserConstant.RedisKey.CACHE_USER_DEVICE + userId + LocalConstant.DeviceType.R);
//        redisUtil.delete(UserConstant.RedisKey.CACHE_USER_DEVICE + userId + LocalConstant.DeviceType.T);
//        redisUtil.delete(UserConstant.RedisKey.CACHE_USER_DEVICE + userId + LocalConstant.DeviceType.X);
        redisUtil.delete(UserConstant.RedisKey.CACHE_USER_DEVICE + LocalConstant.DeviceType.R + userId);
        redisUtil.delete(UserConstant.RedisKey.CACHE_USER_DEVICE + LocalConstant.DeviceType.T + userId);
        redisUtil.delete(UserConstant.RedisKey.CACHE_USER_DEVICE + LocalConstant.DeviceType.X + userId);
    }

    @Override
    public List<Device> listLiveRInfo(String userId, String condition) {
        SearchDeviceParam param = new SearchDeviceParam();
        param.setReceiver(true)
                .setLiving(true)
                .setBookmardIds("all")
                .setCondition(condition);

        List<Device> devices = this.listUserSourceDevices(userId, param);

        return devices;
    }

    @Override
    public List<String> listCacheRPeerId(String userId) {
        String key = String.join("_", new String[]{"userAllR", userId});

        Object rList = rListCacheManager.getIfPresent(key);

        if (!(rList == null || (rList instanceof List && ((List) rList).size() == 0))) {
            if (log.isDebugEnabled()) {
                log.debug("get listCacheRPeerId from memory cache, userId [{}]", userId);
            }
            List<String> rList1 = (List<String>) rList;
            // 因为是 Java 里面的对象，所以要防止引用被改变，这里浅拷贝一下
            List<String> rIds = new ArrayList<>(rList1);
            return rIds;
        }

        List<String> peerIdList = null;
        try {
            peerIdList = this.listUserCacheRids(userId);
        } catch (Exception e) {
            peerIdList = new ArrayList<>(0);
            log.error("Get Redis key [{}]  exception", UserConstant.RedisKey.CACHE_USER_DEVICE + LocalConstant.DeviceType.R + userId, e);
        }



        rListCacheManager.put(key, peerIdList);

        return new ArrayList<>(peerIdList);
    }

    @Override
    public List<String> listSourceAvailableRids(String userId, String sourceId, String sourceType, String condition) {
        Collection<String> rIds = null;

        // Grid available R
        if (LocalConstant.DeviceType.X.equals(sourceType)) {
            // 从 Grid (Grid Market) 服务授权给用户的设备
            // 如果当前查询的 Grid 在这个列表里面,那么查询出来可用的 R 应该是用户下所有可用的 R
            List<String> requestXids = new ArrayList<>();

            try {
                //查询该用户下global grid接收的grid
                List<AcceptedGrid> acceptedGrids = gridService.getGridByUserId(userId, "");
                log.error("===acceptedGrids ==" + JSONObject.toJSONString(acceptedGrids));
                if (!CollectionUtils.isEmpty(acceptedGrids)) {
                    log.info("user [{}] request grid source size [{}]", userId, acceptedGrids.size());
                    requestXids.addAll(acceptedGrids.stream().map(AcceptedGrid::getPeerId).collect(Collectors.toList()));
                } else {
                    log.info("user [{}] request grid source size 0", userId);
                }

            } catch (Exception e) {
                log.error(" Exception getGridByUserId user id [{}]", userId, e);
            }
            if (!CollectionUtils.isEmpty(requestXids)) {
                //如果该grid 包含在用户global grid 接收的grid列表中，则该grid是可以跟用户下所有的R live(不一定配对的也可以）
                if (requestXids.contains(sourceId)) {
                    log.error("===requestXids.contains(sourceId) == true");
                    rIds = listAvailableRIdsByUser(userId, condition);
                }
            }

            if (CollectionUtils.isEmpty(rIds)) {
                rIds = listAvailableRIdsByX(userId, sourceId);
                log.error("===listAvailableRIdsByX ==" + JSONObject.toJSONString(rIds));
            }
            log.info("Grid source paired R size {}", rIds.size());
        } else if (LocalConstant.DeviceType.T.equals(sourceType)) {
            //T available R,包含 token 配对的 R
            rIds = listAvailableRIdsByT(userId, sourceId, condition);
            log.error("===listAvailableRIdsByT ==" + JSONObject.toJSONString(rIds));
            log.error("T paired R size {}", rIds.size());
        } else {
            // Ext available R
            rIds = listAvailableRIdsByUser(userId, condition);
            log.error("===listAvailableRIdsByUser ==" + JSONObject.toJSONString(rIds));
            log.info("Ext user R size {}", rIds.size());
        }

        return new ArrayList<>(rIds);
    }

    @Override
    public List<Device> listSourceAvailableR(String userId, SearchSourcePairedRParam param) {

        String deviceType = param.getDeviceType();
        String condition = param.getCondition();
        String sourceId = param.getSourceId();


        List<String> rIds = this.listSourceAvailableRids(userId, sourceId, deviceType, condition);

    /*    if (rIds == null) {
            rIds = new ArrayList<>(0);
        }*/

        List<Device> devices = null;

        if (rIds.size() > 0) {
            devices = listCurrentDevice(rIds);
        } else {
            devices = new ArrayList<>(0);
        }

        //如果有筛选条件
        if (StringUtils.isNotBlank(condition)) {
            devices = devices.stream()
                    .filter(device -> (StringUtils.containsIgnoreCase(device.getName(), condition)
                            || StringUtils.containsIgnoreCase(device.getPeerId(), condition)))
                    .collect(Collectors.toList());
        }

        // Set living first
        SearchDeviceParam searchDeviceParam = new SearchDeviceParam()
                .setLiveFirst(true);
        sortDevices(devices, searchDeviceParam);

        return devices;
    }

    @Override
    public List<Device> listSourceAvailableRSort(String userId, SearchSourcePairedRParam param) {

        String deviceType = param.getDeviceType();
        String condition = param.getCondition();
        String sourceId = param.getSourceId();


        List<String> rIds = this.listSourceAvailableRids(userId, sourceId, deviceType, condition);

     /*   if (rIds == null) {
            rIds = new ArrayList<>(0);
        }*/

        List<Device> devices = null;

        if (rIds.size() > 0) {
            devices = listCurrentDevice(rIds);
        } else {
            devices = new ArrayList<>(0);
        }

        //如果有筛选条件
        if (StringUtils.isNotBlank(condition)) {
            devices = devices.stream()
                    .filter(device -> (StringUtils.containsIgnoreCase(device.getName(), condition)
                            || StringUtils.containsIgnoreCase(device.getPeerId(), condition)))
                    .collect(Collectors.toList());
        }

        // Set living first
        SearchDeviceParam searchDeviceParam = new SearchDeviceParam()
                .setOnlineFirst(true);
        sortDevices(devices, searchDeviceParam);

        return devices;
    }

    @Override
    public PageInfo<Device> pageSourceAvailableR(String userId, SearchSourcePairedRParam param) {
        List<Device> devices = listSourceAvailableR(userId, param);
        PageInfo<Device> pageInfo = new PageInfo<>();
        pageInfo.setPageNum(param.getPageNum());
        pageInfo.setPageSize(param.getPageSize());
        return packagePageInfo(devices, pageInfo);
    }

    @Override
    public PageInfo<Device> pageSourceAvailableRSort(String userId, SearchSourcePairedRParam param) {
        List<Device> devices = listSourceAvailableRSort(userId, param);
        //sort
        PageInfo<Device> pageInfo = new PageInfo<>();
        pageInfo.setPageNum(param.getPageNum());
        pageInfo.setPageSize(param.getPageSize());
        return packagePageInfo(devices, pageInfo);
    }

    @Override
    public PageInfo<SimpleDeviceVo> pageAllUserRNoStatus(String userId, SearchSourcePairedRParam param) {
        PageHelper.startPage(param.getPageNum(), param.getPageSize());
        String condition = param.getCondition();
        condition = MyUtil.formatCondition(condition);
        List<SimpleDeviceVo> devices = userDeviceMapper.listUserSimpleDevice(userId, condition, LocalConstant.DeviceType.R);

        if (devices == null) {
            devices = new ArrayList<>();
        }

        return new PageInfo<>(devices);
    }


    @Override
    public List<DevicePositionVo> listUserSourcePosition(String userId, String condition, String mapType) {


        // T status
        List<String> tIds = this.listUserDevice(userId, condition, LocalConstant.DeviceType.T);
        List<Device> tStatus = listCurrentDevice(tIds);
        tStatus = tStatus.stream()
                .filter(t -> !LocalConstant.DeviceStatus.OFFLINE.equals(t.getStatus()))// 过滤掉 offline 的设备
                .collect(Collectors.toList());


        List<DevicePositionVo> tDevicePositionVos = new ArrayList<>(JsonUtil.jackson.convertValue(tStatus, new TypeReference<List<DevicePositionVo>>() {
        }));


        // 提取所有的Tid
        List<String> existTIds = tDevicePositionVos.stream().map(DevicePositionVo::getPeerId).collect(Collectors.toList());

        if (existTIds.size() > 0) {
            Map<String, String> tPosition = new HashMap<>();
            List<DeviceGeo> tPositionDetail = deviceGeoMapper.getDevicePositionByPeerIds(existTIds);

            tPositionDetail.forEach(deviceGeo -> {
                String position = "";
                if (deviceGeo.getStatus() == 1) {
                    // automatic
                    position = deviceGeo.getAutomatic();
                } else if (deviceGeo.getStatus() == 2) {
                    // manual
                    position = deviceGeo.getManual();
                } else {
                    // no position
                    position = "0,0";
                }
                tPosition.put(deviceGeo.getPeerId(), position);
            });


            // 为 T 结果加上position
            for (DevicePositionVo tDevicePositionVo : tDevicePositionVos) {
                tDevicePositionVo.setPosition(tPosition.get(tDevicePositionVo.getPeerId()));
            }
        }


        //Grid status
        List<String> xIds = this.listUserDevice(userId, condition, LocalConstant.DeviceType.X);
        List<Device> xStatus = listCurrentDevice(xIds);
        xStatus = xStatus.stream()
                .filter(x -> !LocalConstant.DeviceStatus.OFFLINE.equals(x.getStatus())) // 过滤掉 offline 的设备
                .collect(Collectors.toList());


        List<DevicePositionVo> xDevicePositionVos = new ArrayList<>(JsonUtil.jackson.convertValue(xStatus, new TypeReference<List<DevicePositionVo>>() {
        }));
        if (xStatus.size() > 0) {

            // 提取 产生 X 的 R 的 ID
            List<String> existXIds = xDevicePositionVos.stream()
                    .map(DevicePositionVo::getPeerId)
                    .map(peerId -> peerId.substring(0, 16))
                    .collect(Collectors.toList());

            List<DeviceGeo> xPositionDetail = deviceGeoMapper.getDevicePositionByPeerIds(existXIds);


            Map<String, String> xPosition = new HashMap<>();
            xPositionDetail.forEach(deviceGeo -> {
                String position = "";
                if (deviceGeo.getStatus() == 1) {
                    // automatic
                    position = deviceGeo.getAutomatic();
                } else if (deviceGeo.getStatus() == 2) {
                    // manual
                    position = deviceGeo.getManual();
                } else {
                    // no position
                    position = "0,0";
                }
                //做百度纠偏

                xPosition.put(deviceGeo.getPeerId(), position);

            });

            // 为 X 结果加上position
            for (DevicePositionVo xDevicePositionVo : xDevicePositionVos) {
                xDevicePositionVo.setPosition(xPosition.get(xDevicePositionVo.getPeerId().substring(0, 16)));
            }
        }

        // final result
        xDevicePositionVos.addAll(tDevicePositionVos);
        for (DevicePositionVo xDevicePositionVo : xDevicePositionVos) {
            String position = xDevicePositionVo.getPosition();
            if (StringUtils.isNotEmpty(mapType) && "baidu".equals(mapType)) {
                String[] geoInfoStr = position.split(",");
                double[] geoInfo = GPSUtil.gcj02_To_Bd09(Double.valueOf(geoInfoStr[0]), Double.valueOf(geoInfoStr[1]));
                position = geoInfo[0] + "," + geoInfo[1];
                xDevicePositionVo.setPosition(position);
            }
        }
        return xDevicePositionVos;
    }

    @Override
    public List<DevicePositionVo> getSourceLiveRPosition(String sourceId) {

//        List<String> sourceIds = new ArrayList<>();
//        sourceIds.add(sourceId);
        Device currentDevice = deviceService.getCurrentDevice(sourceId);
        if (currentDevice == null) {
            return new ArrayList<>(0);
        }

        String livePeerId = currentDevice.getLivePeerId();

        // livePeerId 说明没有在live就无法获取到对方的地理位置
        if (StringUtils.isBlank(livePeerId)) {
            return new ArrayList<>(0);
        }

        List<Device> devices = listCurrentDevice(Arrays.asList(livePeerId.split(";")));

        devices = devices.stream()
                .filter(t -> !LocalConstant.DeviceStatus.OFFLINE.equals(t.getStatus()))// 过滤掉 offline 的设备
                .collect(Collectors.toList());


        if (devices.size() == 0) {
            return new ArrayList<>(0);
        }


        List<DevicePositionVo> rDevicePositionVos = new ArrayList<>(JsonUtil.jackson.convertValue(devices, new TypeReference<List<DevicePositionVo>>() {
        }));


        // 提取所有的Tid
        List<String> existRIds = rDevicePositionVos.stream().map(DevicePositionVo::getPeerId).collect(Collectors.toList());

        if (existRIds.size() > 0) {
            Map<String, String> rPosition = new HashMap<>();
            List<DeviceGeo> tPositionDetail = deviceGeoMapper.getDevicePositionByPeerIds(existRIds);

            tPositionDetail.forEach(deviceGeo -> {
                String position = "";
                if (deviceGeo.getStatus() == 1) {
                    // automatic
                    position = deviceGeo.getAutomatic();
                } else if (deviceGeo.getStatus() == 2) {
                    // manual
                    position = deviceGeo.getManual();
                } else {
                    // no position
                    position = "0,0";
                }
                rPosition.put(deviceGeo.getPeerId(), position);
            });


            // 为 R 结果加上position
            for (DevicePositionVo tDevicePositionVo : rDevicePositionVos) {
                tDevicePositionVo.setPosition(rPosition.get(tDevicePositionVo.getPeerId()));
            }
        }
        return rDevicePositionVos;
    }

    @Override
    public List<DeviceExtend> listCurrentDeviceForTaskInfo(String userId, ListDeviceParam param) {
        if (StringUtils.isEmpty(param.getPeerIds())) {
            return new ArrayList<>();
        }
        List<Device> devices = deviceService.listCurrentDevice(Arrays.asList(param.getPeerIds().split(",")));

        // 修正状态
        setSourceLivePeerInfoForUser(userId, devices, true, true);

        // 批量设置 live device 的信息
        List<DeviceExtend> deviceExtends = batchSetExtendInfo(devices);


        return deviceExtends;
    }

    /**
     * 批量设置 Device ExtendInfo
     *
     * @param devices
     * @return
     */
    private List<DeviceExtend> batchSetExtendInfo(List<Device> devices) {
        if (CollectionUtils.isEmpty(devices)) {
            return new ArrayList<>();
        }

        // 如果存在 livePeerId， 批量查询 live 的 source
        StringBuffer livePeerIdBuffer = new StringBuffer();
        for (Device device : devices) {
            String livePeerId = device.getLivePeerId();
            if (StringUtils.isNotEmpty(livePeerId)) {
                livePeerIdBuffer.append(livePeerId).append(",");
            }
        }

        // 把所有的 livePeerId 一起查出来，封装到 Map 中去
        Map<String, Device> liveDeviceMap = new HashMap<>();
        String livePeerIds = livePeerIdBuffer.toString();
        if (livePeerIds.length() > 2) {
            livePeerIds = livePeerIds.substring(0, livePeerIds.length() - 1);
            List<Device> liveDevices = deviceService.listCurrentDevice(Arrays.asList(livePeerIds.split(",")));
            if (!CollectionUtils.isEmpty(liveDevices)) {
                liveDeviceMap = liveDevices.stream().collect(Collectors.toMap(item -> item.getPeerId(), item -> item));
            }
        }

        List<DeviceExtend> deviceExtendList = new ArrayList<>();
        for (Device device : devices) {
            DeviceExtend extend = new DeviceExtend();
            BeanUtils.copyProperties(device, extend);
            String livePeerId = extend.getLivePeerId();
            if (StringUtils.isNotEmpty(livePeerId)) {
                Device liveDevice = liveDeviceMap.get(livePeerId);
                if (liveDevice == null) {
                    // live 的设备查不到，可能是 localSource
                    extend.setLivePeerName(defaultLivePeerName);
                } else {
                    extend.setLivePeerName(liveDevice.getName());
                    extend.setLivePeerType(liveDevice.getType());
                    extend.setLiveDevicePlatform(liveDevice.getPlatform());
                    List<String> extTypes = Arrays.asList(extType.split(","));
                    if (extTypes.contains(liveDevice.getType())) {
                        extend.setLivePeerUrl(liveDevice.getUrl());
                    }
                    extend.setLivePeerVersion(liveDevice.getVersion());
                }
            }
            deviceExtendList.add(extend);
        }
        return deviceExtendList;
    }

    /**
     *
     * @param type type
     * @param deviceId deviceId
     * @param emailId emailId
     * @return String
     */
    public String deviceFeatureList(String type, String deviceId, String emailId) {
        String body = "";
        String rep = "";
        try {
            String url = tpcUrl + "/queryFeatureControlDetail.action?deviceType=" + type + "&peerId=" + deviceId + "&session=" + emailId;
            ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, String.class);
            if (responseEntity.getStatusCodeValue() != 200) {
                log.error("queryFeatureControlDetail failed:result:{}", responseEntity);
            } else {
                body = responseEntity.getBody();

            }
        } catch (RestClientException e) {
            log.error("====queryFeatureControlDetail Exception====" + e);
        }

        if (StringUtils.isNotEmpty(body)) {
            JSONArray jsonArray = JSONArray.parseArray(body);
            JSONObject jsonObject = JSON.parseObject(jsonArray.get(0).toString());
            if (!jsonObject.containsKey("availFeatureList")) {
                return rep;
            }
            JSONArray availFeatureList = JSONArray.parseArray(jsonObject.get("availFeatureList").toString());
            JSONArray availFeatureListRep = JSONArray.parseArray(jsonObject.get("availFeatureList").toString());
            for (int i = 0; i < availFeatureList.size(); i++) {
                JSONObject jsonObjectFeature = JSON.parseObject(availFeatureList.get(i).toString());
                if (!"IFB".equals(jsonObjectFeature.get("name")) && !"TVOIP".equals(jsonObjectFeature.get("name"))) {
                    availFeatureListRep.remove(availFeatureList.get(i));
                }
            }
            if (availFeatureListRep.size() > 0) {
                rep = availFeatureListRep.toJSONString();
            }
            if (availFeatureList.size() > 0) {
                TimeMap.put(deviceId, rep);
            }
        }
        return rep;
    }

    private void setExtendInfo(String userId, String peerId, DeviceExtend deviceExtend, Device temp) throws Exception {
//        UserDeviceOperation userDeviceOperation = new UserDeviceOperation();
//        userDeviceOperation.setUserId(userId);
//        userDeviceOperation.setPeerId(peerId);
//        List<UserDeviceOperation> dex = userDeviceOperationMapper.select(userDeviceOperation);
////        log.error("setExtendInfo UserDeviceOperation Json "+JsonUtil.toJsonStr(dex));
//        if (dex != null && dex.size() > 0) {
//            userDeviceOperation = dex.get(0);
////            log.error("setExtendInfo UserDeviceOperation Json  dex.get(0)"+JsonUtil.toJsonStr(userDeviceOperation));
//            if (userDeviceOperation.getFavorite() != null ) {
//                deviceExtend.setFavorite(String.valueOf(userDeviceOperation.getFavorite()));
//            } else {
//                deviceExtend.setFavorite("0");
//            }
//            if (userDeviceOperation.getDescribes() != null) {
//                deviceExtend.setDescribes(userDeviceOperation.getDescribes());
//            } else {
//                deviceExtend.setDescribes("");
//            }
//        } else {
//            deviceExtend.setDescribes("");
//            deviceExtend.setFavorite("0");
//        }
        if (StringUtils.isBlank(deviceExtend.getLivePeerId())) {
            deviceExtend.setLivePeerName("");
            deviceExtend.setLivePeerType("null");
            deviceExtend.setLiveDevicePlatform("null");
            deviceExtend.setLivePeerUrl("null");
            deviceExtend.setLivePeerVersion("null");
        } else {
            try {
                Device de = null;
                List<Device> devices = deviceService.listCurrentDevice(Arrays.asList(temp.getLivePeerId().split(",")));
                if (devices.size() > 0) {
                    de = devices.get(0);
                }
                if (de != null) {
                    deviceExtend.setLivePeerName(de.getName());
                    deviceExtend.setLivePeerType(de.getType());
                    deviceExtend.setLiveDevicePlatform(de.getPlatform());
                    if ("Ext".equals(de.getType())) {
                        deviceExtend.setLivePeerUrl(de.getUrl());
                    }
                    deviceExtend.setLivePeerVersion(de.getVersion());
                } else {
                    deviceExtend.setLivePeerName(defaultLivePeerName);
                    deviceExtend.setLivePeerType("null");
                    deviceExtend.setLiveDevicePlatform("null");
                    deviceExtend.setLivePeerUrl("null");
                    deviceExtend.setLivePeerVersion("null");
                }
            } catch (Exception e) {
                log.error("msg:{},e:{}",e.getMessage(),e);
                log.error("deviceExtend.setLivePeerName" + e.getMessage());
            }
        }
    }

    @Override
    public List<SearchUserDeviceVo> listSettingPageUserBindDevice(String userId, SearchUserDeviceParam param) {
        String condition = param.getCondition();
        condition = MyUtil.formatCondition(condition);
        param.setCondition(condition);
        String appendSql = param.appendTypeSql();
        param.setAppendSql(appendSql);
        List<SearchUserDeviceVo> list = userDeviceMapper.listSettingPageUserBindDevice(param);
        //判断token是否为true,是的话，需要查询出加入list中
        boolean tokenFlag = param.isToken();
        //查询出token device绑定的设备
        if (tokenFlag) {
            List<SearchUserDeviceVo> queryTokenDeviceList = null;
            List<AnyWhereVo> tokenAnywhereOwner = null;
            try {
                //查询用户下R的所有Token
                List<String> receiverIds = this.listUserCacheRids(param.getUserId());
                if (!CollectionUtils.isEmpty(receiverIds)) {
                    Set<String> tokenAnywhereIds = tokenFeignService.listRsPairedTids(new HashSet<>(receiverIds));
                    tokenAnywhereOwner = tokenFeignService.listParamRsPairedTids(receiverIds);
                        //记录tvu_token_device 表的主键id 到SearchUserDeviceVo 中,回显给前端,授权时根据id去update
                    if (!CollectionUtils.isEmpty(tokenAnywhereIds)) {
                        queryTokenDeviceList = userDeviceMapper.getDeviceByPeerIds(tokenAnywhereIds, condition);
                        for (SearchUserDeviceVo searchUserDeviceVo : queryTokenDeviceList) {
                            for (AnyWhereVo anyWhereVo : tokenAnywhereOwner) {
                                if (StringUtils.equalsIgnoreCase(anyWhereVo.getPeerId(),searchUserDeviceVo.getPeerId())){
                                    searchUserDeviceVo.setId(anyWhereVo.getId());
                                }
                            }
                        }
                    }
                }
            } catch (Exception e) {
                log.error(">>>>>>>>>>>listSettingPageUserBindDevice(queryTokenDeviceList) is error{}", e);
            }
            if (queryTokenDeviceList != null && queryTokenDeviceList.size() > 0) {
                list.addAll(queryTokenDeviceList);
                List<SearchUserDeviceVo> retList = new ArrayList<>();
                List<String> deviceIds = new ArrayList<>();
                //去除重复
                list.forEach(
                        p -> {
                            if (!deviceIds.contains(p.getPeerId())) {
                                deviceIds.add(p.getPeerId());
                                retList.add(p);
                            }
                        }
                );
                this.setRelationAndEnableRelation(userId, retList, false);
                for (SearchUserDeviceVo searchUserDeviceVo : retList) {
                    if (StringUtils.isEmpty(searchUserDeviceVo.getId())){
                        continue;
                    }
                    Boolean ownerDeviceById = tokenFeignService.isOwnerDeviceById(searchUserDeviceVo.getId());
                    if (ownerDeviceById) {
                        searchUserDeviceVo.setRelation(1);
                    } else {
                        //需要再查询是否在tvu_user_device表中是owner权限
                        Boolean ownerByUserIdAndPeerId = this.getOwnerByUserIdAndPeerId(param.getUserId(), searchUserDeviceVo.getPeerId());
                        if (ownerByUserIdAndPeerId){
                            searchUserDeviceVo.setRelation(1);
                            //并且为了保持同步在tvu_token_device中授权
                            tokenFeignService.updateDeviceById(searchUserDeviceVo.getId(), 1);
                        }else {
                            searchUserDeviceVo.setRelation(0);
                        }
                    }
                }
                return retList;
            }
        }
        this.setRelationAndEnableRelation(userId, list, false);
        return list;
    }

    private Boolean getOwnerByUserIdAndPeerId(String userId, String peerId) {
        Integer id = userDeviceMapper.getOwnerByUserIdAndPeerId(userId, peerId);
        if(id>0) {
            return true;
        }
        return false;
    }

    private List<SearchUserDeviceVo> setRelationAndEnableRelation(String userId, List<SearchUserDeviceVo> list, boolean setRelation0) {
        if (CollectionUtils.isEmpty(list)) {
            return list;
        }
        for (SearchUserDeviceVo vo : list) {
            if (setRelation0) {
                vo.setRelation(0);
            }
            boolean isOwner = true;
            if (StringUtils.isNotBlank(userId)) {
                // Support 分配设备时，UserId为空
                isOwner = this.isUserOwner(userId, vo.getPeerId());
            }
            if (isOwner) {
                if (StringUtils.equals(vo.getType(),"X")){
                    vo.setEnableRelation(1);
                }
            } else {
                vo.setEnableRelation(0);
            }

            if (LocalConstant.DeviceType.R.equalsIgnoreCase(vo.getType())) {
                vo.setEnableRelation(1);
            }
        }
        return list;
    }


    @Override
    public List<SearchUserDeviceVo> listSettingPageUserCanBindDevice(SearchUserDeviceParam param) {
        String searchUser = null;

        String condition = param.getCondition();
        condition = MyUtil.formatCondition(condition);
        param.setCondition(condition);
        String userId = param.getUserId();
        User user = userService.getById(userId);
        if (user == null) {
            return new ArrayList<>();
        }
        String appendSql = param.appendTypeSql();
        param.setAppendSql(appendSql);
        // 需要被修改的用户
        String role = user.getRole();
        List<SearchUserDeviceVo> allVos = new ArrayList<>();
        if (StringUtils.equals(LocalConstant.UserRole.ADMIN, role)) {
            // Support为admin分配设备
            // 查询不在admin账号下的设备
            allVos = userDeviceMapper.listSettingPageSupportDevice(param);
            if (allVos == null || allVos.size() == 0) {
                return new ArrayList<>();
            }
            List<SearchUserDeviceVo> bindVos = userDeviceMapper.listSettingPageUserBindDevice(param);
            if (bindVos != null && bindVos.size() > 0) {
                allVos.removeAll(bindVos);
            }
        } else if (StringUtils.equals(LocalConstant.UserRole.USER, role)) {
            // admin为user分配设备
            // 查询在admin下，但是不在user下的设备
            String userParentId = user.getUserParentId();
            if (StringUtils.isBlank(userParentId)) {
                log.error("ListSettingPageUserCanBindDevice failed, distribute device to user, but user do not have parent, userId:[{}]", userId);
                return new ArrayList<>();
            }
            searchUser = userParentId;

            param.setUserId(userParentId);
            allVos = userDeviceMapper.listSettingPageUserBindDevice(param);
            if (allVos == null || allVos.size() == 0) {
                return new ArrayList<>();
            }
            param.setUserId(userId);
            List<SearchUserDeviceVo> bindVos = userDeviceMapper.listSettingPageUserBindDevice(param);
            if (bindVos != null && bindVos.size() > 0) {
                allVos.removeAll(bindVos);
            }
        }
        return setRelationAndEnableRelation(searchUser, allVos, true);
    }


    @Override
    public List<SearchUserDeviceVo> listSettingPageUserCanBindDeviceByUserName(String userId, String email) {
        // 邮箱不存在，抛出异常
        User searchUser = userService.getByEmail(email);
        if (searchUser == null) {
            throw new ClientException("User not exist");
        }
        // 用户不存在，返回空
        User needBindUser = userService.getById(userId);
        if (needBindUser == null) {
            return new ArrayList<>();
        }
        String role = needBindUser.getRole();
        if (StringUtils.equals(LocalConstant.UserRole.USER, role)) {
            // 为user账户分配设备，需要校验搜索的用户是否能为当前user分配设备
            String searchUserRole = searchUser.getRole();
            if (StringUtils.equals(LocalConstant.UserRole.ADMIN, searchUserRole)) {
                // 搜索用户是admin
                // 如果搜索用户不是被绑定用户的父亲，返回空
                if (!StringUtils.equals(needBindUser.getUserParentId(), searchUser.getId())) {
                    return new ArrayList<>();
                }
            } else if (StringUtils.equals(LocalConstant.UserRole.USER, role)) {
                // 搜索用户是user
                // 如果搜索用户和被绑定用户不是同一个父亲，返回空
                if (!StringUtils.equals(needBindUser.getUserParentId(), searchUser.getUserParentId())) {
                    return new ArrayList<>();
                }
            } else {
                return new ArrayList<>();
            }
        } else if (StringUtils.equals(LocalConstant.UserRole.SUPPORT, role) || StringUtils.equals(LocalConstant.UserRole.SUPER_ADMIN, role)) {
            return new ArrayList<>();
        }

        // 查询搜索账户中的所有设备
        List<String> allPids = userDeviceMapper.listUserRTXIds(searchUser.getId());
        if (CollectionUtils.isEmpty(allPids)) {
            return new ArrayList<>();
        }
        // 去掉被绑定用户自身拥有的设备
        List<String> bindedPids = userDeviceMapper.listUserRTXIds(userId);
        if (!CollectionUtils.isEmpty(bindedPids)) {
            allPids.removeAll(bindedPids);
        }
        if (CollectionUtils.isEmpty(allPids)) {
            return new ArrayList<>();
        }
        List<SearchUserDeviceVo> allVos = userDeviceMapper.listSearchUserDeviceVoByPids(allPids);
        return setRelationAndEnableRelation(userId, allVos, true);
    }

    @Override
    public List<SearchUserDeviceVo> listCanBindDeviceBySalesForce(String userId, String account) {
        User user = userService.getById(userId);
        if (user == null) {
            return new ArrayList<>();
        }
        if (!StringUtils.equals(LocalConstant.UserRole.ADMIN, user.getRole())) {
            // SalesForce途径 只允许Support给Admin分配设备
            return new ArrayList<>();
        }

        // SalesForce查询到的所有设备
        List<String> allPids = tvuSalesforceFeignService.salesForceQueryAccountDeviceList(account);
        if (CollectionUtils.isEmpty(allPids)) {
            return new ArrayList<>();
        }
        // 去掉被绑定用户自身拥有的设备
        List<String> bindedPids = userDeviceMapper.listUserRTXIds(userId);
        if (!CollectionUtils.isEmpty(bindedPids)) {
            allPids.removeAll(bindedPids);
        }
        if (CollectionUtils.isEmpty(allPids)) {
            return new ArrayList<>();
        }
        List<SearchUserDeviceVo> allVos = userDeviceMapper.listSearchUserDeviceVoByPids(allPids);
        return setRelationAndEnableRelation(userId, allVos, true);
    }

    @Override
    public List<SearchUserDeviceVo> listSettingPageUserPairedDevice(String userId, String peerId) {
        Device device = deviceService.getCurrentDevice(peerId);
        if (device == null || StringUtils.isEmpty(device.getType())) {
            return new ArrayList<>();
        }
        // 封装参数，调用上面的接口
        SearchUserDeviceParam param = new SearchUserDeviceParam()
                .setUserId(userId);
        if (StringUtils.equals(LocalConstant.DeviceType.R, device.getType())) {
            param.setPack(true)
                    .setAnywhere(true)
                    .setGridPack(true)
                    .setGridSdi(true);
        } else {
            param.setReceiver(true);
        }

        // 账户下的设备
        List<SearchUserDeviceVo> allVos = this.listSettingPageUserCanBindDevice(param);
        if (allVos == null || allVos.size() == 0) {
            return new ArrayList<>();
        }


        // 有配对关系的设备
        List<String> pairedIds = new ArrayList<>();
        if (StringUtils.equals(LocalConstant.DeviceType.R, device.getType())) {
            List<String> rPairT = deviceFeignService.listRPairT(peerId);
            if (rPairT != null && rPairT.size() > 0) {
                pairedIds.addAll(rPairT);
            }
            List<String> rPairX = deviceFeignService.listRPairX(peerId);
            if (rPairX != null && rPairX.size() > 0) {
                pairedIds.addAll(rPairX);
            }
        } else if (StringUtils.equals(LocalConstant.DeviceType.T, device.getType())) {
            List<String> tPairR = deviceFeignService.listTPairR(peerId);
            if (tPairR != null && tPairR.size() > 0) {
                pairedIds.addAll(tPairR);
            }
        } else if (StringUtils.equals(LocalConstant.DeviceType.X, device.getType())) {
            List<String> xPairR = deviceFeignService.listXPairR(peerId);
            if (xPairR != null && xPairR.size() > 0) {
                pairedIds.addAll(xPairR);
            }
        }

        // 取交集
        List<SearchUserDeviceVo> resultList = new ArrayList<>();
        for (SearchUserDeviceVo vo : allVos) {
            if (pairedIds.contains(vo.getPeerId())) {
                vo.setRelation(0);
                resultList.add(vo);
            }
        }
        return resultList;
    }

    @Override
    @Transactional
    public void correlateUserDevice(String userId, String addPeerIds, String removePeerIds, String addOwnPeerIds, String removeOwnPeerIds, String loginUserId) {
        this.correlateUserDevice(userId, addPeerIds, removePeerIds, addOwnPeerIds, removeOwnPeerIds, loginUserId, false);
    }

    @Override
    public void correlateUserDevice(String userId, String addPeerIds, String removePeerIds, String addOwnPeerIds, String removeOwnPeerIds, String loginUserId, boolean relateSource) {

        User user = userService.getById(userId);
        if (user == null) {
            return;
        }
        String role = user.getRole();
        if (!(LocalConstant.UserRole.ADMIN.equals(role) || LocalConstant.UserRole.USER.equals(role))) {
            // 非 Adam 和 User 不能分配设备
            return;
        }
        // add UserDevice
        if (StringUtils.isNotBlank(addPeerIds)) {
            String[] peerIds = addPeerIds.split(",");

            // 暂时使用线程池上线，等待加百利修复
            UserThreadPool.SERVICETHREADPOOL.execute(() -> {
                for (String peerId : peerIds) {
                    if (StringUtils.isNotBlank(loginUserId)) {
                        //判断设备是token的device,如果是,则执行，否则执行之前的逻辑(用户id是当前登录用户的id)
                        boolean flag = judgeIsTokenDevice(peerId, loginUserId);
                        if (flag) {
                            //向token device中新增数据(分享的用户id)
                            addTokenDevice(peerId, userId, loginUserId, 0);
                        }
                    }
                }
            });

            List<String> list = Arrays.asList(peerIds);
            HashSet<String> peerIdSet = new HashSet<>(list);
            addUserDevices(userId, peerIdSet, role);
            if (relateSource) {
                this.addRPairedTXToUser(userId, peerIdSet);
            }
        }
        List<String> sonIds = null;
        // remove UserDevice
        // 如果移除Admin的设备，需要同时移除孩子的设备
        List<String> willRemoveUserIds = new ArrayList<>();
        willRemoveUserIds.add(userId);
        if (StringUtils.equals(LocalConstant.UserRole.ADMIN, role)) {
            sonIds = userMapper.listSonUserIds(userId);
            if (!CollectionUtils.isEmpty(sonIds)) {
                willRemoveUserIds.addAll(sonIds);
            }
        }
        if (StringUtils.isNotBlank(removePeerIds)) {
            String[] peerIds = removePeerIds.split(",");

            // 暂时使用线程池上线，等待加百利修复
            UserThreadPool.SERVICETHREADPOOL.execute(() -> {
                for (String peerId : peerIds) {
                    //判断移除的设备是否为token device(是，则操作tvu_token_device表数据,userId为绑定的user id)
                    boolean flag = judgeIsTokenDevice(peerId, userId);
                    if (flag) {
                        removeTokenDevice(peerId, userId);
                    }
                }
            });

            List<String> peerIdList = Arrays.asList(peerIds);
            List<String> ids = userDeviceMapper.listIdInUsersAndPeerIds(willRemoveUserIds, peerIdList);
            if (!CollectionUtils.isEmpty(ids)) {
                userDeviceMapper.deleteByIdList(ids);
                // 移除 R 和 Ext 的关系
                this.removeUserRExtRelation(userId, peerIdList);

                // 移除 R token 配对关系
                this.removeReceiverTokenPair(userId, peerIdList);

                //移除在role_manage中设置过的设备
                roleManagementService.deleteByUserIdAndPeerId(userId, peerIdList);


                if (relateSource) {
                    //    this.removeRPairedTXToUser(userId, peerIdList);
                    for (String willRemoveUserId : willRemoveUserIds) {
                        this.removeRPairedTXToUser(willRemoveUserId, peerIdList);
                    }
                }
            }

        }

        // 添加Owner关系
        if (StringUtils.isNotBlank(addOwnPeerIds)) {
            String[] peerIds = addOwnPeerIds.split(",");
            for (String peerId : peerIds) {
                setOwner(userId, peerId, 1);
            }
        }

        // 移除Owner关系
        if (StringUtils.isNotBlank(removeOwnPeerIds)) {
            String[] peerIds = removeOwnPeerIds.split(",");
            for (String peerId : peerIds) {
                setOwner(userId, peerId, 0);

                if (!CollectionUtils.isEmpty(sonIds)) {
                    for (String sonId : sonIds) {
                        setOwner(sonId, peerId, 0);
                    }
                }
            }

        }
        this.removeUserCacheDevice(userId);
    }


    /**
     * addPeerIds 中的 R 找寻配对的 X 和 T 加上
     *
     * @param userId
     * @param peerIds
     */
    private void addRPairedTXToUser(String userId, Collection<String> peerIds) {
        try {
            if (!correlateUserDeviceEnableRRelation) {
                log.error("addRPairedTXToUser correlateUserDeviceEnableRRelation is false return step1, userId:[{}] peerIds:[{}]", userId, peerIds);
                return;
            }

            if (userId == null || CollectionUtils.isEmpty(peerIds)) {
                log.error("addRPairedTXToUser param error return step2, userId:[{}] peerIds:[{}]", userId, peerIds);
                return;
            }

            boolean userExistFeature = userFeatureService.isUserExistFeatureName(userId, disableReceiverCentricFeature);
            if (userExistFeature) {
                log.error("addRPairedTXToUser user exist disableReceiverCentricFeature Feature return step1.5, userId:[{}] peerIds:[{}]", userId, peerIds);
                return;
            }

            Set<String> pids = new HashSet<>(peerIds);
            List<Device> devices = deviceService.listCurrentDevice(pids);
            if (CollectionUtils.isEmpty(devices)) {
                log.error("addRPairedTXToUser devices is null return step3, userId:[{}] peerIds:[{}]", userId, peerIds);
                return;
            }
            Set<String> rids = devices.stream().filter(d -> LocalConstant.DeviceType.R.equalsIgnoreCase(d.getType())).map(Device::getPeerId).collect(Collectors.toSet());
            if (CollectionUtils.isEmpty(rids)) {
                log.error("addRPairedTXToUser rids is null return step4, userId:[{}] peerIds:[{}]", userId, peerIds);
                return;
            }
            Set<String> needAddedSids = new HashSet<>();
            if (correlateUserDeviceEnableRRelationT) {
                try {
                    Set<String> tids = this.listRsPairTids(rids);
                    log.error("addRPairedTXToUser deviceFeignService.listRsPairTids step5, userId:[{}] peerIds:[{}] tids:[{}]", userId, peerIds, tids);
                    if (!CollectionUtils.isEmpty(tids)) {
                        needAddedSids.addAll(tids);
                    }
                } catch (Exception e) {
                    log.error(e.toString(), e);
                }
            }
            if (correlateUserDeviceEnableRRelationX) {
                try {
                    Set<String> xids = this.listRsPairedXids(rids);
                    log.error("addRPairedTXToUser gcsManageFeignService.listRsPairedXids step6, userId:[{}] peerIds:[{}] xids:[{}]", userId, peerIds, xids);
                    if (!CollectionUtils.isEmpty(xids)) {
                        needAddedSids.addAll(xids);
                    }
                } catch (Exception e) {
                    log.error(e.toString(), e);
                }
            }
            if (CollectionUtils.isEmpty(needAddedSids)) {
                log.error("addRPairedTXToUser needAddedSids is null return step7, userId:[{}] peerIds:[{}]", userId, peerIds);
                return;
            }
            List<String> userDeviceIds = this.listUserCacheDeviceIds(userId);
            needAddedSids.removeAll(userDeviceIds);
            if (CollectionUtils.isEmpty(needAddedSids)) {
                log.error("addRPairedTXToUser needAddedSids is null return step8, userId:[{}] peerIds:[{}]", userId, peerIds);
                return;
            }

            String role = LocalConstant.UserRole.ADMIN;
            User user = userService.getById(userId);
            if (user != null) {
                role = user.getRole();
            }
            log.error("addRPairedTXToUser final add source step9, userId:[{}] peerIds:[{}] needAddedSids:[{}]", userId, peerIds, needAddedSids);
            this.addUserDevices(userId, needAddedSids, role);
        } catch (Exception e) {
            log.error(e.toString(), e);
        }
    }

    /**
     * removePeerIds 中的 R 找寻配对的 X 和 T 移除
     *
     * @param userId
     * @param peerIds
     */
    private void removeRPairedTXToUser(String userId, Collection<String> peerIds) {
        try {
            if (!correlateUserDeviceEnableRRelation) {
                log.error("removeRPairedTXToUser correlateUserDeviceEnableRRelation is false return step1, userId:[{}] peerIds:[{}]", userId, peerIds);
                return;
            }
            if (userId == null || CollectionUtils.isEmpty(peerIds)) {
                log.error("removeRPairedTXToUser param error return step2, userId:[{}] peerIds:[{}]", userId, peerIds);
                return;
            }

            boolean userExistFeature = userFeatureService.isUserExistFeatureName(userId, disableReceiverCentricFeature);
            if (userExistFeature) {
                log.error("removeRPairedTXToUser user exist disableReceiverCentricFeature Feature return step1.5, userId:[{}] peerIds:[{}]", userId, peerIds);
                return;
            }

            Set<String> pids = new HashSet<>(peerIds);
            List<Device> devices = deviceService.listCurrentDevice(pids);
            if (CollectionUtils.isEmpty(devices)) {
                log.error("removeRPairedTXToUser devices is null return step3, userId:[{}] peerIds:[{}]", userId, peerIds);
                return;
            }
            Set<String> rids = devices.stream().filter(d -> LocalConstant.DeviceType.R.equalsIgnoreCase(d.getType())).map(Device::getPeerId).collect(Collectors.toSet());
            if (CollectionUtils.isEmpty(rids)) {
                log.error("removeRPairedTXToUser rids is null return step4, userId:[{}] peerIds:[{}]", userId, peerIds);
                return;
            }

            List<String> allRids = this.listUserCacheRids(userId);
            allRids.removeAll(rids);
            Set<String> remainRids = new HashSet<>(allRids);

            Set<String> needRemovedSids = new HashSet<>();
            if (correlateUserDeviceEnableRRelationT) {
                try {
                    Set<String> tids = this.listRsPairTids(rids);
                    log.error("removeRPairedTXToUser deviceFeignService.listRsPairTids step5, userId:[{}] peerIds:[{}] tids:[{}]", userId, peerIds, tids);
                    Set<String> remainTids = this.listRsPairTids(remainRids);
                    log.error("removeRPairedTXToUser deviceFeignService.listRsPairTids step6, userId:[{}] peerIds:[{}] remainTids:[{}]", userId, peerIds, remainTids);
                    tids.removeAll(remainTids);
                    log.error("removeRPairedTXToUser need remove tids step7, userId:[{}] peerIds:[{}] needRemove tids:[{}]", userId, peerIds, tids);
                    if (!CollectionUtils.isEmpty(tids)) {
                        needRemovedSids.addAll(tids);
                    }
                } catch (Exception e) {
                    log.error(e.toString(), e);
                }
            }
            if (correlateUserDeviceEnableRRelationX) {
                try {
                    Set<String> xids = this.listRsPairedXids(rids);
                    log.error("removeRPairedTXToUser gcsManageFeignService.listRsPairedXids step8, userId:[{}] peerIds:[{}] xids:[{}]", userId, peerIds, xids);
                    Set<String> remainXids = this.listRsPairedXids(remainRids);
                    log.error("removeRPairedTXToUser gcsManageFeignService.listRsPairedXids step9, userId:[{}] peerIds:[{}] remainXids:[{}]", userId, peerIds, remainXids);
                    xids.removeAll(remainXids);
                    log.error("removeRPairedTXToUser need remove rids step10, userId:[{}] peerIds:[{}] needRemove xids:[{}]", userId, peerIds, xids);
                    if (!CollectionUtils.isEmpty(xids)) {
                        needRemovedSids.addAll(xids);
                    }
                } catch (Exception e) {
                    log.error(e.toString(), e);
                }
            }
            if (CollectionUtils.isEmpty(needRemovedSids)) {
                log.error("removeRPairedTXToUser needRemovedSids is null return step11, userId:[{}] peerIds:[{}]", userId, peerIds);
                return;
            }
            List<String> userDeviceIds = this.listUserCacheDeviceIds(userId);
            needRemovedSids.retainAll(userDeviceIds);
            if (CollectionUtils.isEmpty(needRemovedSids)) {
                log.error("removeRPairedTXToUser needRemovedSids is null return step12, userId:[{}] peerIds:[{}]", userId, peerIds);
                return;
            }
            log.error("removeRPairedTXToUser final need source step13, userId:[{}] peerIds:[{}] needRemovedSids:[{}]", userId, peerIds, needRemovedSids);
            List<String> ids = userDeviceMapper.listIdInUsersAndPeerIds(Arrays.asList(new String[]{userId}), new ArrayList<>(needRemovedSids));
            if (!CollectionUtils.isEmpty(ids)) {
                userDeviceMapper.deleteByIdList(ids);
            }
        } catch (Exception e) {
            log.error(e.toString(), e);
        }
    }

    /**
     *
     * @param email email
     * @param loginUserId loginUserId
     * @param operationType operationType
     * @param param param
     */
    public void saveUserDeviceRecord(String email, String loginUserId, String operationType, Map param) {
        //账号和设备关系入库
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    String userIdList = param.get("userIdList").toString();
                    String peerIdList = param.get("peerIdList").toString();
                    String[] userIdListArr = userIdList.split(",");
                    String[] peerIdListArr = peerIdList.split(",");
                    UserDeviceRecord userDeviceRecord = new UserDeviceRecord();
                    userDeviceRecord.setId(distributedGlobalIdUtil.netxId() + "");
                    userDeviceRecord.setCreateTime(System.currentTimeMillis() + "");
                    userDeviceRecord.setRequestId(distributedGlobalIdUtil.netxId() + "");
                    userDeviceRecord.setUserId(loginUserId);//当前操作登录的用户
                    userDeviceRecord.setUserEmail(email);//绑定或者一除设备的用户
                    userDeviceRecord.setDeleteFlag(0);
                    userDeviceRecord.setParam("");
                    //对请求参数判断是什么操作类型
                    userDeviceRecord.setOperationType(operationType);
                    for (String userId : userIdListArr) {
                        userDeviceRecord.setAccount(userId);
                        for (String peerId : peerIdListArr) {
                            userDeviceRecord.setPeerId(peerId);
                            deviceFeignService.saveUserDeviceRecord(userDeviceRecord);
                        }
                    }
                } catch (Exception e) {
                    log.error("deviceFeignService.saveUserDeviceRecord Exception", e);
                }
            }
        }).start();
    }


    //向token device新增数据 userId指的是需要分配的userid
    private void addTokenDevice(String peerId, String userId, String loginUserId,int owner) {
        //根据登录用户id和peerId,来确定一个最大过期时间的token code(定时任务将token 过期时根据code来移除绑定关系)
        String code = "";
        try {
            code = userDeviceMapper.getMaxExipreCode(peerId, loginUserId);
        } catch (Exception e) {
            log.error(">>>>>>>>>>>>addTokenDevice(getMaxExipreCode) is error{}", e);
        }
        if (StringUtils.isEmpty(code)) {
            return;
        }
        // 操作tokenDevice表(主要通过用户id和状态获取到配对的anywhere)
        TokenDevice tokenDeviceParam = new TokenDevice();
        tokenDeviceParam.setId(MyUtil.getUUID());
        //标识1:通过setting分享的token,后期类似于分享的code码也变化,容易区分
        tokenDeviceParam.setCode("1");
        tokenDeviceParam.setPeerId(peerId);
        tokenDeviceParam.setType(TokenConstant.TOKEN_TYPE_T);
        tokenDeviceParam.setDeleteFlag(TokenConstant.NOT_DELETED);
        tokenDeviceParam.setCreateTime(System.currentTimeMillis());
        tokenDeviceParam.setStatus(3);
        tokenDeviceParam.setReminded(0);
        tokenDeviceParam.setExpireFlag(TokenConstant.NOT_EXPIRED);
        tokenDeviceParam.setUserId(userId);
        tokenDeviceParam.setOwner(owner);
        try {
            userDeviceMapper.saveTokenDevice(tokenDeviceParam);
        } catch (Exception e) {
            log.error(">>>>>>>>>>>>addTokenDevice is error{}", e);

        }
    }

    //移除token device的数据(根据设备id和用户id移除即可)
    private void removeTokenDevice(String peerId, String userId) {
        try {
            userDeviceMapper.removeTokenDevice(peerId, userId);
        } catch (Exception e) {
            log.error(">>>>>>>>>>>>removeTokenDevice is error{}", e);
        }
    }

    //判断是否为token device设备
    private boolean judgeIsTokenDevice(String peerId, String userId) {
        List<SearchUserDeviceVo> queryTokenDeviceList = null;
        boolean flag = false;
        try {
            queryTokenDeviceList = userDeviceMapper.queryTokenDeviceList(peerId, userId);
            if (queryTokenDeviceList != null && queryTokenDeviceList.size() > 0) {
                flag = true;
            }
        } catch (Exception e) {
            log.error(">>>>>>>>>judgeIsTokenDevice is error{}", e);
        }
        return flag;
    }

    @Override
    public boolean existUserBindDevice(String addPeerIds) {
        if (StringUtils.isBlank(addPeerIds)) {
            return false;
        }
        String[] peerIds = addPeerIds.split(",");
        for (String peerId : peerIds) {
            UserDevice rd = new UserDevice().setPeerId(peerId);
            List<UserDevice> existList = userDeviceMapper.select(rd);
            if (!CollectionUtils.isEmpty(existList)) {
                return true;
            }
        }
        return false;
    }

    private void addUserDevices(String userId, Set<String> peerIds, String role) {
        if (CollectionUtils.isEmpty(peerIds)) {
            return;
        }
        List<String> userOwnPeerIds = this.listUserCacheDeviceIds(userId);
        if (!CollectionUtils.isEmpty(userOwnPeerIds)) {
            peerIds.removeAll(userOwnPeerIds);
        }


        List<UserDevice> addList = new ArrayList<>();
        for (String peerId : peerIds) {
            UserDevice ud = new UserDevice()
                    .setUserId(userId)
                    .setPeerId(peerId)
                    .setRelation(0)
                    .setPostion(0)
                    .setFlag(0)
                    .setId(MyUtil.getUUID());
            addList.add(ud);
            UserDevice ud2 = new UserDevice();
            BeanUtils.copyProperties(ud, ud2);
            ud2.setId(MyUtil.getUUID())
                    .setFlag(StringUtils.equals(LocalConstant.UserRole.ADMIN, role) ? 1 : 2);
            addList.add(ud2);
        }
        if (CollectionUtils.isEmpty(addList)) {
            return;
        }

        int listSize = addList.size();
        for (int i = 0; i < listSize; i += 100) {
            int end = i + 100 > listSize ? listSize : i + 100;
            userDeviceMapper.insertList(addList.subList(i, end));
        }

    }


    private void setOwner(String userId, String peerId, int relation) {
        if (StringUtils.isBlank(peerId)) {
            return;
        }
        List<String> peerIds = new ArrayList<>();
        Device currentDevice = deviceFeignService.getCurrentDevice(peerId);

        if (peerId.length() == 16 && StringUtils.equalsIgnoreCase(currentDevice.getType(),"R")) {
            peerIds.add(peerId);
            peerIds.add(peerId + gridPack);
            peerIds.add(peerId + gridSdi);
        } else {
            peerIds.add(peerId);
        }
        for (String pid : peerIds) {
            UserDevice record = new UserDevice()
                    .setUserId(userId)
                    .setPeerId(pid);
            List<UserDevice> existList = userDeviceMapper.select(record);
            if (CollectionUtils.isEmpty(existList)) {
                continue;
            }
            for (UserDevice userDevice : existList) {
                userDevice.setRelation(relation);
                userDeviceMapper.updateByPrimaryKeySelective(userDevice);
            }
        }

    }

    @Override
    public boolean isUserOwnDevice(String userId, String peerId) {
        UserDevice record = new UserDevice()
                .setUserId(userId)
                .setPeerId(peerId);
        List<UserDevice> list = userDeviceMapper.select(record);
        return !CollectionUtils.isEmpty(list);
    }

    /**
     *
     * @param userId userId
     * @param peerId peerId
     * @return List
     */
    public List<UserDevice> checkUserBindWithDevice(String userId, String peerId) {
        UserDevice record = new UserDevice()
                .setUserId(userId)
                .setPeerId(peerId);
        List<UserDevice> list = userDeviceMapper.select(record);
        return list;
    }

    @Override
    public List<BindDeviceUserVo> listDeviceBindUser(String peerId) {
        return userDeviceMapper.listDeviceBindUser(peerId);
    }


    /**
     * 查询grid token 的配对状态
     *
     * @param userId userId
     * @param allDevice allDevice
     */
    private void setGridTokenStatus(String userId, List<Device> allDevice) {

        if (allDevice == null || allDevice.size() == 0) {
            return;
        }

        if (log.isDebugEnabled()) {
            log.debug("Check grid token paired status userId [{}]", userId);
        }

        TokenRequest tokenRequestCondition = new TokenRequest();
        tokenRequestCondition.setUserId(userId);
        for (Device device : allDevice) {
            if (LocalConstant.DeviceType.X.equals(device.getType())) {
                tokenRequestCondition.setXId(device.getPeerId());
                Integer gridTokenPairStatus = tokenService.getGridTokenPairStatus(tokenRequestCondition);
                device.setTokenStatus(gridTokenPairStatus);
            }
        }
    }


    private List<String> listUserAcceptGridTokenRequest(String userId, int status) {
        List<String> list = (List<String>) redisUtil.get(cacheUserGridTokenKey + status + userId);
        if (list != null) {
            return list;
        }
        list = tokenRequestMapper.listUserGridTokenRequest(userId, status);
        redisUtil.set(cacheUserGridTokenKey + status + userId, list, cacheUserGridTokenTime);
        return list;
    }


    /**
     * 批量查询 GridTokenStatus
     *
     * @param userId userId
     * @param peerIds peerIds
     * @return Map  key:peerId value:gridStatus
     */
    @Override
    public Map<String, Integer> batchGetGridTokenStatus(String userId, List<String> peerIds) {
        if (CollectionUtils.isEmpty(peerIds)) {
            return new HashMap<>(0);
        }

        // 过滤掉不是 X 的设备
        Set<String> allXPeerIds = peerIds.stream().filter(e -> e.length() == 32).filter(e -> (e.contains(gridPack) || e.contains(gridSdi))).collect(Collectors.toSet());
        if (CollectionUtils.isEmpty(peerIds)) {
            return new HashMap<>(0);
        }

        // 查询当前用户各个状态的 GridToken
        List<String> acceptList = this.listUserAcceptGridTokenRequest(userId, LocalConstant.GridTokenPairStatus.ACCEPT);
        List<String> waitList = this.listUserAcceptGridTokenRequest(userId, LocalConstant.GridTokenPairStatus.WAIT);
        List<String> rejectList = this.listUserAcceptGridTokenRequest(userId, LocalConstant.GridTokenPairStatus.REJECT);

        // 和请求过来的 peerIds 做交集，返回
        Map<String, Integer> map = new HashMap<>();
        acceptList.retainAll(allXPeerIds);
        waitList.retainAll(allXPeerIds);
        rejectList.retainAll(allXPeerIds);

        for (String peerId : rejectList) {
            map.put(peerId, LocalConstant.GridTokenPairStatus.REJECT);
        }
        for (String peerId : waitList) {
            map.put(peerId, LocalConstant.GridTokenPairStatus.WAIT);
        }
        for (String peerId : acceptList) {
            map.put(peerId, LocalConstant.GridTokenPairStatus.ACCEPT);
        }

        return map;
    }

    @Override
    public DeviceBelongUserDTO listDeviceBelongUserForAlertDeviceChange(String peerId) {
        Device device = deviceService.getCurrentDevice(peerId);
        if (device == null) {
            log.error("listDeviceBelongUserForAlertDeviceChange failed device not exist peerId:{}", peerId);
            return null;
        }
        String type = device.getType();
        if (type == null) {
            log.error("listDeviceBelongUserForAlertDeviceChange failed device type is null peerId:{} device:{}", peerId, device);
            return null;
        }
        List<String> alertTypes = Arrays.asList(alertDeviceChangeTypes.split(","));
        if (!alertTypes.contains(type)) {
            return null;
        }
        List<String> userIds = this.listCacheDeviceBelongUser(peerId);
        DeviceBelongUserDTO dto = new DeviceBelongUserDTO(device, userIds);
        return dto;
    }

    @Override
    public ChannelUsingCount channelCount(String userId, boolean manual) {
        List<String> userAllRs = this.listCacheRPeerId(userId);

        // TODO
        // 1.根据 manual 区分出手动/自动 R
        // 2.根据 R status 判断出状态  1:useable  2:using 0:offline
        // manual = true手动
        List<String> autoPeerIds = customizedDeviceFeignService.listAutoPeerIds();
        if (autoPeerIds == null) {
            autoPeerIds = new ArrayList<>();
        }

        if (manual) {
            userAllRs.removeAll(autoPeerIds);
        } else {
            userAllRs.retainAll(autoPeerIds);
        }

        int all = userAllRs.size();
        int useable = 0;
        int using = 0;
        int offline = 0;

        // 批量查询 memcache
        List<Device> devices = deviceService.listCurrentDevice(userAllRs);

        if (CollectionUtils.isEmpty(devices)) {
            devices = new ArrayList<>(0);
        }
        for (Device device : devices) {
            if (device != null) {
                if (device.getStatus().equalsIgnoreCase("1")) {
                    useable++;
                } else if (device.getStatus().equalsIgnoreCase("2")) {
                    using++;
                }
            }
        }

        // 离线的 Device 可能 memcache 中查不到，所以计算出 online 和 living 的 R 之后，用减法算出离线的设备
        offline = all - useable - using;

        ChannelUsingCount channelUsingCount = new ChannelUsingCount().setAll(all).setOffline(offline).setUsing(using).setUseable(useable);
        return channelUsingCount;
    }

    @Override
    public PageInfo<Device> pageBookingChannel(PageBookingChannelParam param) {
        String peerId = param.getSid();
        String condition = param.getCondition();
        String userId = param.getUserId();

        // 用户所有 R
        List<String> userRids = this.listUserCacheRids(userId);

        if (StringUtils.isNotBlank(peerId)) {
            Device source = deviceService.getCurrentDevice(peerId);
            if (source != null) {
                // 查询用户和 Source 有配对的 R
                userRids = this.listSourceAvailableRids(userId, peerId, source.getType(), condition);
                if (CollectionUtils.isEmpty(userRids)) {
                    return new PageInfo<>(new ArrayList<>(0));
                }
            } else {
                // Source 为空 可能是 UGC
            }
        }

        if (enableCustomizedCC) {
            String userGroupId = param.getUserGroupId();
            if (StringUtils.isNotBlank(userGroupId)) {
                String groupName = customizedUserGroupService.getGroupNameById(userGroupId);
                if (StringUtils.isBlank(groupName)) {
                    // Group 不存在
                    ServerException.Exception(ResultConstant.CustomizedUserGroup.GROUP_NOT_EXIST);
                }
                // 过滤掉和 Source 不是一个分组的 R
                customizedUserDeviceGroupService.filterDeviceByGroupName(userId, groupName, userRids);
            }

            int auto = param.getAuto();
            // 自动通道所有 R
            List<String> autoRids = customizedDeviceFeignService.listAutoPeerIds();
            if (autoRids == null) {
                autoRids = new ArrayList<>();
            }
            if (auto == 0) {
                userRids.removeAll(autoRids);
            } else {
                userRids.retainAll(autoRids);
            }
        }

        if (CollectionUtils.isEmpty(userRids)) {
            return new PageInfo<>(new ArrayList<>(0));
        }
        PageHelper.startPage(param.getPageNum(), param.getPageSize());
        List<Device> devices = userDeviceMapper.listDevice(userRids, condition);
        return new PageInfo<>(devices);
    }


    /**
     * 查询 Grid 可用的R（配对的包含用户下的R）
     * 查询方法:
     * 1.先在 JVM 内存中查询是否有缓存的结果 {@link CacheConfiguration#rListCacheManager()}
     * 2.在缓存中查询用户下的所有的R
     * 3.调 grid server 的接口查询配对的R
     * 4. 2 retainAll 3 取交集
     * 5.set 到缓存中
     * <p>
     * <p>
     * 使用此方法需要注意:
     * 1.grid 正在 live 的 r 一定是在grid server 中配对过的，如果想查询正在live的R是否是当前用户下的直接用live peer id
     * 和用户下的 R list 取交集即可，不要调用此方法
     *
     * @param userId userId
     * @param gridId grid id
     * @return List
     */
    private List<String> listAvailableRIdsByX(String userId, String gridId) {

        String key = String.join("_", new String[]{"xPaired", userId, gridId});

        // 先看缓存中是否有结果
        Object ifPresent = rListCacheManager.getIfPresent(key);

        if (ifPresent != null) {
            if (log.isDebugEnabled()) {
                log.debug("get listAvailableRIdsByX from memory cache, userId [{}]", userId);
            }
            return (List<String>) ifPresent;
        }


        // 在 memcache 中查询用户下的所有的R
        List<String> cacheRPeerId = listCacheRPeerId(userId);

        // 因为是 Java 里面的对象，所以要防止引用被改变，这里浅拷贝一下
        List<String> rIds = new ArrayList<>(cacheRPeerId);

        List<String> pairedR = null;
        try {
            // 调 grid server 的接口查询配对的 R
            pairedR = deviceFeignService.listXPairR(gridId);

        } catch (Exception e) {
            log.error(" Exception get listXPairR gridId", gridId, e);
        }


        if (rIds != null && pairedR != null) {
            // 取交集
            rIds.retainAll(pairedR);
        } else {
            // 及时获取的结果为 null 也要缓存结果，防止缓存穿透
            rIds = new ArrayList<>(0);
        }

        rListCacheManager.put(key, rIds);
        return rIds;
    }

    /**
     * 查询 T 可用的R（配对的包含用户下的R）
     *
     * @param userId userId
     * @param tId    T id pack,anywhere
     * @return Collection
     */
    private Collection<String> listAvailableRIdsByT(String userId, String tId, String condition) {
        List<String> rIds = this.listUserDevice(userId, condition, LocalConstant.DeviceType.R);
        List<String> pairedR = deviceFeignService.listTPairR(tId);

        if (rIds != null && pairedR != null) {
            rIds.retainAll(pairedR);
        } else {
            rIds = new ArrayList<>(0);
        }

        // 查询 token 配对的 R
        Set<String> tokenPairR = tokenFeignService.listTokenTPairedR(tId);

        rIds.addAll(tokenPairR);

        return new HashSet<>(rIds);
    }

    /**
     * Ext 可用的R可用的R（配对的包含用户下的R）
     *
     * @param userId userId
     * @param condition 查询条件
     * @return List
     */
    private List<String> listAvailableRIdsByUser(String userId, String condition) {
        List<String> rIds = this.listUserDevice(userId, condition, LocalConstant.DeviceType.R);

        if (rIds == null) {
            rIds = new ArrayList<>(0);
        }

        return rIds;
    }


    private String packageTypeCondition(SearchDeviceParam param) {
        StringBuilder typeString = new StringBuilder();
        if (param.isReceiver()) {
            typeString.append(" OR d.type = 'R'");
        }

        if (param.isPack() || param.isAnywhere()) {
            typeString.append(" OR ( ");
            typeString.append(" d.type = 'T'");
            if (!param.isPack()) {
                typeString.append(" AND d.platform != '' AND d.platform >= 10 AND d.platform <= 14");
            }
            if (!param.isAnywhere()) {
                typeString.append(" AND d.platform != '' AND (d.platform < 10 OR d.platform > 14)");
            }
            typeString.append(")");
        }
        if (param.isGridPack() || param.isGridSdi()) {
            typeString.append(" OR (");
            typeString.append(" d.type = 'X'");
            if (!param.isGridPack()) {
                typeString.append(" AND d.peer_id LIKE '%0000000000000002'");
            }
            if (!param.isGridSdi()) {
                typeString.append(" AND d.peer_id LIKE '%0000000000000001'");
            }
            typeString.append(" )");
        }
        if (param.isExt()) {
            typeString.append(" OR d.type in ('Ext','YouTube','SMPTE2022','FILE','SRT')");
        }
        typeString.append(" )");
        String result = typeString.toString().substring(3);
        return "(" + result;
    }

    @Override
    public Result<Object> queryTokenDeviceList(LoginUser loginUser, String peerIdOrName, String userId) throws Exception {
        //1.判断loginUser
        if (loginUser == null) {
            return ResultUtil.noLogin();
        }
        //2.根据 peerIdOrName 和当前登录用户 id 查询 token device
        List<String> peerIds = tokenFeignService.queryCurrentUserPairTid(loginUser.getId(), peerIdOrName);
        if (CollectionUtils.isEmpty(peerIds)) {
            return ResultUtil.success(new ArrayList<>(0));
        }

        //判断搜索的设备是否已经处于绑定到当前待分享的账户中
        List<String> existPeerIds = this.listUserCacheDeviceIds(userId);

        if (!CollectionUtils.isEmpty(existPeerIds)) {
            peerIds.removeAll(existPeerIds);
        }

        if (CollectionUtils.isEmpty(peerIds)) {
            return ResultUtil.success(new ArrayList<>(0));
        }

        List<Device> devices = deviceService.listCurrentDevice(peerIds);
        if (CollectionUtils.isEmpty(devices)) {
            return ResultUtil.success(new ArrayList<>(0));
        }
        List<SearchUserDeviceVo> resultList = new ArrayList<>(devices.size());
        for (Device device : devices) {
            resultList.add(JsonUtil.convertValue(device, SearchUserDeviceVo.class));
        }
        return ResultUtil.success(resultList);

    }

    @Override
    public boolean isUserOwner(String userId, String peerId) {
        Device device = deviceService.getCurrentDevice(peerId);
        if (device == null) {
            return false;
        }
      /*  if (!LocalConstant.DeviceType.X.equals(device.getType())) {
            return false;
        }*/
        User user = userService.getById(userId);
        if (user == null) {
            return false;
        }
        String userRole = user.getRole();
        if (LocalConstant.UserRole.SUPER_ADMIN.equals(userRole) || LocalConstant.UserRole.SUPPORT.equals(userRole)) {
            return true;
        }
        UserDevice record = new UserDevice()
                .setUserId(userId)
                .setPeerId(peerId)
                .setRelation(1);
        List<UserDevice> list = userDeviceMapper.select(record);
        return !CollectionUtils.isEmpty(list);
    }

    @Override
    @Transactional
    public int copyDeviceToNewDevice(String oldPeerId, String newPeerId, boolean gridSource, boolean deleteOld, String taskId) {
        if (StringUtils.isBlank(oldPeerId) || StringUtils.isBlank(newPeerId)) {
            log.error("Start copyDevice copy UserDevice failed paramError taskId:[{}] oldPeerId:[{}] newPeerId:[{}]", taskId, oldPeerId, newPeerId);
            // 参数错误
            return 1;
        }
        if (StringUtils.equalsIgnoreCase(oldPeerId, newPeerId)) {
            // peerId 相同
            return 4;
        }
        Device oldDevice = deviceService.getCurrentDevice(oldPeerId);
        if (oldDevice == null) {
            log.error("Start copyDevice copy UserDevice failed oldDevice is null taskId:[{}] oldPeerId:[{}] newPeerId:[{}]", taskId, oldPeerId, newPeerId);
            return 2;
        }
        Device newDevice = deviceService.getCurrentDevice(newPeerId);
        if (newDevice == null) {
            log.error("Start copyDevice copy UserDevice failed newDevice is null taskId:[{}] oldPeerId:[{}] newPeerId:[{}]", taskId, oldPeerId, newPeerId);
            return 3;
        }
        Set<String> userIds = this.copyUserDevice(oldPeerId, newPeerId, deleteOld, taskId);
        if (userIds == null) {
            userIds = new HashSet<>();
        }
        if (gridSource) {
            Device oldPack = deviceService.getCurrentDevice(oldPeerId + gridPack);
            Device newPack = deviceService.getCurrentDevice(newPeerId + gridPack);
            if (oldPack != null && newPack != null) {
                Set<String> packUserIds = this.copyUserDevice(oldPeerId + gridPack, newPeerId + gridPack, deleteOld, taskId);
                if (!CollectionUtils.isEmpty(packUserIds)) {
                    userIds.addAll(packUserIds);
                }
            }
            Device oldSdi = deviceService.getCurrentDevice(oldPeerId + gridSdi);
            Device newSdi = deviceService.getCurrentDevice(newPeerId + gridSdi);
            if (oldSdi != null && newSdi != null) {
                Set<String> sdiUserIds = this.copyUserDevice(oldPeerId + gridSdi, newPeerId + gridSdi, deleteOld, taskId);
                if (!CollectionUtils.isEmpty(sdiUserIds)) {
                    userIds.addAll(sdiUserIds);
                }
            }
        }
        for (String userId : userIds) {
            this.removeUserCacheDevice(userId);
        }
        return 0;
    }

    @Override
    public boolean isUserDeviceExist(String userId, String peerId) {
        UserDevice record = new UserDevice().setUserId(userId).setPeerId(peerId);
        List<UserDevice> list = userDeviceMapper.select(record);
        return !CollectionUtils.isEmpty(list);
    }

    @Override
    public void addUserDevice(String userId, String peerId) {
        this.correlateUserDevice(userId, peerId, null, null, null, null);
    }

    @Override
    public void removeUserDevice(String userId, String peerId) {
        this.correlateUserDevice(userId, null, peerId, null, null, null);
    }

    /**
     * 返回受影响的 UserIds
     *
     * @param oldPeerId oldPeerId
     * @param newPeerId newPeerId
     * @return Set
     */
    private Set<String> copyUserDevice(String oldPeerId, String newPeerId, boolean deleteOld, String taskId) {
        List<String> containBothDeviceUser = userDeviceMapper.containBothDeviceUser(oldPeerId, newPeerId);
        if (!CollectionUtils.isEmpty(containBothDeviceUser)) {
            // 两个设备都有的用户，在这里需要删掉新设备的 UserDevice 关系，因为 Grid 存在 Owner 关系，需要用旧的覆盖新的
            userDeviceMapper.removeDevivecBindUser(containBothDeviceUser, newPeerId);
            log.error("Start copyDevice copy UserDevice remove new UserDevice taskId:[{}] containBothDeviceUser:[{}] newPeerId:[{}]", taskId, containBothDeviceUser, newPeerId);
        }

        UserDevice record = new UserDevice()
                .setPeerId(oldPeerId);
        List<UserDevice> list = userDeviceMapper.select(record);

        if (CollectionUtils.isEmpty(list)) {
            return null;
        }
        List<UserDevice> copyList = new ArrayList<>();
        // 记录受影响的用户，用于统一更新缓存
        Set<String> userIds = new HashSet<>();
        for (UserDevice userDevice : list) {
            userIds.add(userDevice.getUserId());
            UserDevice copy = new UserDevice();
            BeanUtils.copyProperties(userDevice, copy);
            copy.setPeerId(newPeerId)
                    .setId(MyUtil.getUUID());
            copyList.add(copy);
        }
        log.error("Start copyDevice copy UserDevice add new UserDevices taskId:[{}] copyList:[{}]", taskId, copyList);
        //这里做分批处理
        if (copyList.size() > deviceCopeSize) {
            int forSize = copyList.size() / deviceCopeSize;
            int modSize = copyList.size() % deviceCopeSize;
            if (modSize > 0) {
                forSize = copyList.size() / deviceCopeSize + 1;
            }
            for (int i = 0; i < forSize; i++) {
                int start = i * deviceCopeSize;
                int end = i * deviceCopeSize + deviceCopeSize;
                if (end > copyList.size()) {
                    end = copyList.size();
                }
                List<UserDevice> copyListSub = copyList.subList(start, end);
                userDeviceMapper.insertList(copyListSub);
            }
        } else {
            userDeviceMapper.insertList(copyList);
        }
        if (deleteOld) {
            // 删除旧设备 UserDevice
            userDeviceMapper.delete(record);
            log.error("Start copyDevice copy UserDevice delete old UserDevice byRecord taskId:[{}] record:[{}]", taskId, record);
        }
        return userIds;
    }


    @Override
    public List<VoDevice> getUnBindVoReceiverList(LoginUser user) throws Exception {
        List<Device> unBindDevice = getUnBindReceiverList(user);
        updateAndSortDeviceStatus(unBindDevice);
        List<VoDevice> voDevideList = new ArrayList<VoDevice>();
        if (unBindDevice != null && unBindDevice.size() > 0) {
            for (Device device : unBindDevice) {
                VoDevice voDevice = getVoDeviceFromDevice(device);
                voDevideList.add(voDevice);
            }
        }
        return voDevideList;
    }

    private VoDevice getVoDeviceFromDevice(Device device) {
        if (device != null) {
            return new VoDevice(device.getPeerId(), device.getName(), device.getStatus(), device.getVersion(), device.getIp(), device.getLivePeerId(), device.getLivePeerName());
        } else {
            return null;
        }
    }

    private void updateAndSortDeviceStatus(List<Device> list) {
        if (list != null) {
            for (int i = 0; i < list.size(); i++) {
                try {
                    Device temp = deviceService.getCurrentDevice(list.get(i).getPeerId());
                    if (temp != null) {
                        if (temp.getPlatform() != null && !"".equals(temp.getPlatform())) {
                            list.get(i).setPlatform(temp.getPlatform());
                        }
                        if (temp.getStatus() != null) {
                            list.get(i).setStatus(temp.getStatus());
                        } else {
                            list.get(i).setStatus("0");
                        }
                        list.get(i).setIp(temp.getIp());
                        list.get(i).setLivePeerId(temp.getLivePeerId());
                        list.get(i).setLivePeerName(temp.getLivePeerName());
                        list.get(i).setName(temp.getName());
                        list.get(i).setPort(temp.getPort());
                        list.get(i).setType(temp.getType());
                        list.get(i).setVersion(temp.getVersion());
                    } else {
                        list.get(i).setStatus("0");
                    }
                } catch (Exception e) {
                    log.error("=== updateAndSortDeviceStatus Exception====", e);
                }
            }
            sortList(list);
        }
    }

    private void sortList(List<Device> list) {
        if (list != null && list.size() > 0) {
            for (Device device : list) {
                if (device.getStatus() != null && !device.getStatus().equals("")) {
                    if (device.getStatus().equals("22")) {
                        device.setPostion(1);
                    } else if (device.getStatus().equals("3")) {
                        device.setPostion(2);
                    } else if (device.getStatus().equals("2")) {
                        device.setPostion(3);
                    } else if (device.getStatus().equals("1")) {
                        device.setPostion(4);
                    } else if (device.getStatus().equals("0")) {
                        device.setPostion(5);
                    }
                } else {
                    device.setPostion(6);
                }
            }
        }
        if(list!=null && list.size()>0){
            Collections.sort(list, new ComparatorPostion());
        }
    }

    @Override
    public List<String> getAllLivePeerIdList(LoginUser user) throws Exception {
        // current peerIdList
        List<String> livePeerIdList = new ArrayList<String>();
        // get all child peerId list
        List<String> childPeerIdList = getAllLivePeerIdList(user.getId());
        // if parent account exist,get all devices belong to parent account.
        String userParentId = user.getUserParentId();
        if (StringUtils.isNotBlank(userParentId)) {
            // parent account exist filter the devices that not exist in parent account.
            List<String> parentPeerIdList = userDeviceMapper.getBindTRPeerIdList(userParentId);
            if (parentPeerIdList != null && parentPeerIdList.size() > 0) {
                for (String peerId : childPeerIdList) {
                    if (parentPeerIdList.contains(peerId)) {
                        livePeerIdList.add(peerId);
                    }
                }
            }
        } else {
            // parent account don't exist
            livePeerIdList = childPeerIdList;
        }

        return livePeerIdList;
    }

    @Override
    public List<String> listOwnerPeerIds(String userId) {
        return userDeviceMapper.listOwnerPeerIds(userId);
    }

    @Override
    public Result<String> checkCopy(String oldPeerId, String newPeerId, String taskId) {
        // 1. Check UserDevice
        List<String> userIds = userDeviceMapper.listUserIdsInPeerId1NotInPeerId2(oldPeerId, newPeerId);
        if (!CollectionUtils.isEmpty(userIds)) {
            log.error("CheckCopyDevice copy UserDevice Receiver failed taskId:[{}] oldPeerId:[{}] newPeerId:[{}] old exist userIds:[{}]", taskId, oldPeerId, newPeerId, userIds);
            return ResultUtil.error("81002101", "Copy User Receiver failed");
        }
        userIds = userDeviceMapper.listUserIdsInPeerId1NotInPeerId2(oldPeerId + gridPack, newPeerId + gridPack);
        if (!CollectionUtils.isEmpty(userIds)) {
            log.error("CheckCopyDevice copy UserDevice Grid Pack failed taskId:[{}] oldPeerId:[{}] newPeerId:[{}] old exist userIds:[{}]", taskId, oldPeerId, newPeerId, userIds);
            return ResultUtil.error("81002102", "Copy User Grid Pack failed");
        }
        userIds = userDeviceMapper.listUserIdsInPeerId1NotInPeerId2(oldPeerId + gridSdi, newPeerId + gridSdi);
        if (!CollectionUtils.isEmpty(userIds)) {
            log.error("CheckCopyDevice copy UserDevice Grid Sdi failed taskId:[{}] oldPeerId:[{}] newPeerId:[{}] old exist userIds:[{}]", taskId, oldPeerId, newPeerId, userIds);
            return ResultUtil.error("81002103", "Copy User Grid Sdi failed");
        }
        // 2. Check BookmarkDevice
        List<String> bookmarkIds = bookmarkDeviceMapper.listBoomarkIdsInPeerId1NotInPeerId2(oldPeerId, newPeerId);
        if (!CollectionUtils.isEmpty(bookmarkIds)) {
            log.error("CheckCopyDevice copy BookmarkDevice Receiver failed taskId:[{}] oldPeerId:[{}] newPeerId:[{}] old exist userIds:[{}]", taskId, oldPeerId, newPeerId, userIds);
            return ResultUtil.error("81002104", "Copy User Receiver Bookmark failed");
        }
        bookmarkIds = bookmarkDeviceMapper.listBoomarkIdsInPeerId1NotInPeerId2(oldPeerId + gridPack, newPeerId + gridPack);
        if (!CollectionUtils.isEmpty(bookmarkIds)) {
            log.error("CheckCopyDevice copy BookmarkDevice Grid Pack failed taskId:[{}] oldPeerId:[{}] newPeerId:[{}] old exist userIds:[{}]", taskId, oldPeerId, newPeerId, userIds);
            return ResultUtil.error("81002105", "Copy User Grid Pack Bookmark failed");
        }
        bookmarkIds = bookmarkDeviceMapper.listBoomarkIdsInPeerId1NotInPeerId2(oldPeerId + gridSdi, newPeerId + gridSdi);
        if (!CollectionUtils.isEmpty(bookmarkIds)) {
            log.error("CheckCopyDevice copy BookmarkDevice Grid Pack failed taskId:[{}] oldPeerId:[{}] newPeerId:[{}] old exist userIds:[{}]", taskId, oldPeerId, newPeerId, userIds);
            return ResultUtil.error("81002106", "Copy User Grid Sdi Bookmark failed");
        }
        return ResultUtil.success();
    }

    @Override
    public Result<String> copyDevice(String oldPeerId, String newPeerId, String taskId) {
        // 1. Copy UserDevice
        this.copyDeviceToNewDevice(oldPeerId, newPeerId, true, false, taskId);
        // 2. Copy BookmarkDevice
        bookmarkDeviceService.copyDevice(oldPeerId, newPeerId, taskId);
        bookmarkDeviceService.copyDevice(oldPeerId + gridPack, newPeerId + gridPack, taskId);
        bookmarkDeviceService.copyDevice(oldPeerId + gridSdi, newPeerId + gridSdi, taskId);
        return ResultUtil.success();
    }

    @Override
    public Result<String> deleteDevice(String peerId, String taskId) {
        return ResultUtil.success();
    }

    @Override
    public Map<String, Object> groupForAdvanceControl(String userId, SearchDeviceParam param) {

      //  String rId = param.getRid();
/*
        if (StringUtils.isEmpty(rId)) {
            Map<String, Object> emptyResult = new HashMap<>();
            emptyResult.put("sourcePack", new PageInfo<>(new ArrayList<>()));
            emptyResult.put("sourceGrid", new PageInfo<>(new ArrayList<>()));
            emptyResult.put("sourceExt", new PageInfo<>(new ArrayList<>()));
            emptyResult.put("totalPackNumber", 0);
            emptyResult.put("totalGridNumber", 0);
            emptyResult.put("totalExtNumber", 0);
        }*/


        SearchDeviceParam initParam = null;
        initParam = param;
        // 完整的数据没有经过任何的筛选条件
        List<Device> devices = listUserSourceDevices(userId, initParam);
        sortDevices(devices, param);

        if (CollectionUtils.isEmpty(devices)) {
            return new HashMap<>();
        }


        //分页过滤grid
        List<Device> grid = devices.stream().filter(x -> StringUtils.equalsIgnoreCase(x.getType(), LocalConstant.DeviceType.X))
                .collect(Collectors.toList());

        PageInfo<Device> pageInfoGrid = new PageInfo<Device>();

        int startPage = (param.getPageNum() - 1) * param.getPageSize();
        pageInfoGrid.setTotal(grid.size());
        if (startPage == 0) {
            grid = grid.stream().limit(param.getPageSize()).collect(Collectors.toList());
        } else {
            grid = grid.stream().skip(startPage).limit(param.getPageSize()).collect(Collectors.toList());
        }
        pageInfoGrid.setList(grid);


        //分页过滤Pack
        PageInfo<Device> pageInfoPack = new PageInfo<Device>();
        List<Device> pack = devices.stream().filter(x -> StringUtils.equalsIgnoreCase(x.getType(), LocalConstant.DeviceType.T))
                .collect(Collectors.toList());

        pageInfoPack.setTotal(pack.size());
        if (startPage == 0) {
            pack = pack.stream().limit(param.getPageSize()).collect(Collectors.toList());
        } else {
            pack = pack.stream().skip(startPage).limit(param.getPageSize()).collect(Collectors.toList());
        }
        pageInfoPack.setList(pack);


        //分页过滤Ext
        List<String> extTypes = Arrays.asList(extType.split(","));
        List<Device> ext = devices.stream().filter(x -> {
                    for (String type : extTypes) {
                        if (StringUtils.equalsIgnoreCase(x.getType(), type)) {
                            return true;
                        }
                    }
                    return false;
                }
        ).collect(Collectors.toList());

        PageInfo<Device> pageInfoExt = new PageInfo<Device>();
        pageInfoExt.setTotal(ext.size());
        if (startPage == 0) {
            ext = ext.stream().limit(param.getPageSize()).collect(Collectors.toList());
        } else {
            ext = ext.stream().skip(startPage).limit(param.getPageSize()).collect(Collectors.toList());
        }
        pageInfoExt.setList(ext);


        log.error("==time==" + System.currentTimeMillis() + "==groupForAdvanceControl param record==userId==" + userId + "====param===" + JSON.toJSONString(param));

        Map<String, Object> result = new HashMap<>();

        result.put("sourcePack", pageInfoPack);
        result.put("sourceGrid", pageInfoGrid);
        result.put("sourceExt", pageInfoExt);
        result.put("totalPackNumber", pageInfoPack.getTotal());
        result.put("totalGridNumber", pageInfoGrid.getTotal());
        result.put("totalExtNumber", pageInfoExt.getTotal());

        return result;
    }

    @Override
    public List<String> listUserPeerIds(ListUserPeerIdsParam param) {
        if (StringUtils.isBlank(param.getUserId())) {
            return new ArrayList<>(0);
        }
        List<String> peerIdList ;
        if (StringUtils.isEmpty(param.getCondition()) && param.getTypes().size() == 0 && param.getPlatforms().size() == 0) {
            peerIdList = listUserCacheDeviceIds(param.getUserId());
        } else {
            peerIdList = userDeviceMapper.listUserPeerIds(param);
        }
        return peerIdList;
    }


    private List<String> getAllLivePeerIdList(String userId) throws Exception {
        List<String> resultList = new ArrayList<String>();
        List<String> tList = userDeviceMapper.getTListByUser(userId);
        if (tList != null && tList.size() > 0) {
            for (String peerId : tList) {
                Device device = deviceService.getCurrentDevice(peerId);
                if (device != null && "2".equals(device.getStatus())) {
                    resultList.add(peerId);
                }
            }
        }
        return resultList;
    }

    /**
     *
     * @param user user
     * @return List
     * @throws Exception 编译异常
     */
    public List<Device> getUnBindReceiverList(LoginUser user) throws Exception {
        List<Device> unBindDevice = userDeviceMapper.getUnBindReceiverList(user.getId());
        return unBindDevice;
    }

    /**
     *
     * @param peerId peerId
     */
    public void deleteGrid(String peerId) {
        try {
            String url = "http://" + gridmarketUrl + "/openapi/deleteGrid";
            Map<String, String> param = new HashMap<>();
            param.put("rId", peerId);
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            headers.add(LocalConstant.API_HEADER_PARAM_KEY, accessServerUtil.generatorAccess());
            HttpEntity httpEntity = new HttpEntity(JsonUtil.toJsonStr(param), headers);
            ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, httpEntity, String.class);
            if (responseEntity.getStatusCodeValue() != 200) {
                log.error("grid/openapi/deleteGrid failed:result:{}", responseEntity);
            } else {
                log.error("grid/openapi/deleteGrid success :result:{}", responseEntity);

            }
        } catch (Exception e) {
            log.error("====grid/openapi/deleteGrid Exception====" + e);
        }

    }

    @Override
    public List<Device> listDeviceOfUser(String userId, SearchDeviceParam param) {
        log.error("listDeviceOfUser>>>>>>>>>>> userId:[{}], param:[{}]", userId, param);
        Set<String> allPeerIds = new HashSet<>();
        //1.获取用户下指定的设备
        List<String> sourcePeerIds = this.listUserPeerIdFilterByTypeAndCondition(userId, param);
        if (!CollectionUtils.isEmpty(sourcePeerIds)) {
            allPeerIds.addAll(sourcePeerIds.stream().map(String::toLowerCase).collect(Collectors.toList()));
        }
        //2.获取token配对的anywhere
        if (param.isAnywhere()) {
            List<String> tokenAnywhereIds = this.getTokenAnywhereIds(userId, null, Boolean.FALSE, param.getCondition(), Boolean.FALSE);
            if (!CollectionUtils.isEmpty(tokenAnywhereIds)) {
                allPeerIds.addAll(tokenAnywhereIds.stream().map(String::toLowerCase).collect(Collectors.toList()));
            }
        }
        //3.返回所有的device
        if (CollectionUtils.isEmpty(allPeerIds)) {
            return new ArrayList<>();
        }
        log.error("listDeviceOfUser>>>>>>>>getUserDevice size:[{}],userId:[{}]", allPeerIds.size(), userId);
        return deviceService.listCurrentDevice(allPeerIds);
    }

    @Override
    public List<Device> listUserDevice(PageUserDeviceParam param) {
        String userId = param.getUserId();
        List<String> peerIds = new ArrayList<>();

        if (param.isReceiver()) {
            List<String> rids = this.listUserRids(userId);
            peerIds.addAll(rids);
        }
        if (param.isAllX()) {
            List<String> rids = this.listUserXids(userId);
            peerIds.addAll(rids);
        } else {
            if (param.isGridPack() || param.isGridSdi()) {
                List<String> xids = this.listUserXids(userId);
                if (param.isGridPack()) {
                    xids = xids.stream().filter(i -> i.endsWith(gridPack)).collect(Collectors.toList());
                } else {
                    xids = xids.stream().filter(i -> i.endsWith(gridSdi)).collect(Collectors.toList());
                }
                peerIds.addAll(xids);
            }
        }
        List<Device> devices = deviceService.listCurrentDevice(peerIds);
        if (CollectionUtils.isEmpty(devices)) {
            return new ArrayList<>(0);
        }
        devices = devices.stream().filter(device -> {

            if (!param.isStatusExist(device.getStatus())) {
                return false;
            }

            String condition = param.getCondition();
            if (StringUtils.isNotBlank(condition)) {
                if (!(StringUtils.containsIgnoreCase(device.getPeerId(), condition)
                        || StringUtils.containsIgnoreCase(device.getName(), condition)
                        || StringUtils.containsIgnoreCase(device.getResourceId(), condition))) {
                    return false;
                }
            }
            return true;
        }).collect(Collectors.toList());
        return devices;
    }

    @Override
    public void removeUserAllDevice(String userId) {
        if (StringUtils.isBlank(userId)) {
            return;
        }
        UserDevice userDevice = new UserDevice();
        userDevice.setUserId(userId);
        log.error("removeUserAllDevice userId:[{}]", userId);
        userDeviceMapper.delete(userDevice);
        this.removeUserCacheDevice(userId);
    }

    @Override
    public PageInfo<Device> pageUserUnbindRPairedSource(PageUserUnbindRPairedSourceParam param) {
        String rid = param.getRid();
        Set<String> rids = new HashSet<>();
        rids.add(rid);
        Set<String> allPeerIds = new HashSet<>();
        Set<String> tids = this.listRsPairTids(rids);
        if (!CollectionUtils.isEmpty(tids)) {
            allPeerIds.addAll(tids);
        }
        Set<String> xids = this.listRsPairedXids(rids);
        if (!CollectionUtils.isEmpty(xids)) {
            allPeerIds.addAll(xids);
        }
        if (CollectionUtils.isEmpty(allPeerIds)) {
            return new PageInfo<>(new ArrayList<>());
        }
        List<String> userDeviceIds = this.listUserCacheDeviceIds(param.getUserId());
        if (!CollectionUtils.isEmpty(userDeviceIds)) {
            allPeerIds.removeAll(userDeviceIds);
        }
        if (CollectionUtils.isEmpty(allPeerIds)) {
            return new PageInfo<>(new ArrayList<>());
        }
        List<Device> devices = deviceService.listCurrentDevice(allPeerIds);
        if (CollectionUtils.isEmpty(devices)) {
            return new PageInfo<>(new ArrayList<>());
        }
        PageInfo<Device> pageInfo = MyUtil.packagePageInfo(devices, param.getPageNum(), param.getPageSize());
        return pageInfo;
    }

    private void addAndRemoveRPair(AddAndRemoveRPairParam param, String operationType, String operateUserId) {
        String taskId = MyUtil.getUUID();
        log.error("addAndRemoveRPair start, param:[{}] taskId:[{}] operationType:[{}] operateUserId:[{}]", param, taskId, operationType, operateUserId);
        String rid = param.getRid();
        List<String> sidList = param.getSids();
        if (StringUtils.isBlank(rid) || CollectionUtils.isEmpty(sidList)) {
            log.error("addAndRemoveRPair param error, param:[{}] taskId:[{}] operationType:[{}] operateUserId:[{}]", param, taskId, operationType, operateUserId);
            return;
        }
        List<String> userIds = userDeviceMapper.listExistDeviceUser(rid);
        if (CollectionUtils.isEmpty(userIds)) {
            log.error("addAndRemoveRPair no user exist r, param:[{}] taskId:[{}] operationType:[{}] operateUserId:[{}]", param, taskId, operationType, operateUserId);
            return;
        }
        boolean add = param.isOperate();
        for (String userId : userIds) {

            boolean userExistFeature = userFeatureService.isUserExistFeatureName(userId, disableReceiverCentricFeature);
            if (userExistFeature) {
                log.error("addAndRemoveRPair user exist disableReceiverCentricFeature Feature return, param:[{}] taskId:[{}] operationType:[{}] operateUserId:[{}]", param, taskId, operationType, operateUserId);
                continue;
            }

            String userRole = LocalConstant.UserRole.USER;
            String userEmail = "";
            User user = userService.getById(userId);
            if (user == null) {
                log.error("addAndRemoveRPair not exist user, param:[{}] userId:[{}] taskId:[{}]", param, userId, taskId);
            } else {
                userRole = user.getRole();
                userEmail = user.getEmail();
            }

            String operateUserEmail = "";
            User operateUser = userService.getById(operateUserId);
            if (operateUser == null) {
                log.error("addAndRemoveRPair not exist operateUser, param:[{}] operateUserId:[{}] taskId:[{}]", param, operateUserId, taskId);
            } else {
                operateUserEmail = operateUser.getEmail();
            }
            List<String> sids = new ArrayList<>(sidList);
            if (add) {
                List<String> existSids = this.listUserCacheDeviceIds(userId);
                sids.removeAll(existSids);
                if (CollectionUtils.isEmpty(sids)) {
                    log.error("addAndRemoveRPair add and user already exist sids, continue, param:[{}] userId:[{}] taskId:[{}]", param, userId, taskId);
                    continue;
                }
                log.error("addAndRemoveRPair call addUserDevices, param:[{}] userId:[{}] sids:[{}] role:[{}] taskId:[{}]", param, userId, sids, userRole, taskId);
                this.addUserDevices(userId, new HashSet<>(sids), userRole);

                String requestId = distributedGlobalIdUtil.netxId() + "";
            //    List<UserDeviceRecord> userDeviceRecords = new ArrayList<>();
                for (String sid : sids) {
                    UserDeviceRecord userDeviceRecord = new UserDeviceRecord();
                    userDeviceRecord.setId(distributedGlobalIdUtil.netxId() + "");
                    userDeviceRecord.setCreateTime(System.currentTimeMillis() + "");
                    userDeviceRecord.setRequestId(requestId);
                    userDeviceRecord.setAccount(userId);
                    userDeviceRecord.setUserId(operateUserId);
                    userDeviceRecord.setUserEmail(operateUserEmail);
                    userDeviceRecord.setDeleteFlag(0);
                    userDeviceRecord.setParam("");
                    userDeviceRecord.setOperationType(operationType);
                    userDeviceRecord.setPeerId(sid);
                //    userDeviceRecords.add(userDeviceRecord);
                    userDeviceRecordService.saveRecord(userDeviceRecord);
                }
//                deviceFeignService.saveUserDeviceRecords(userDeviceRecords);
            } else {
                List<String> existSids = this.listUserCacheDeviceIds(userId);
                existSids.retainAll(sids);
                if (CollectionUtils.isEmpty(existSids)) {
                    log.error("addAndRemoveRPair remove and user not exist sids, continue, param:[{}] userId:[{}] taskId:[{}]", param, userId, taskId);
                    continue;
                }
                List<String> rids = this.listUserCacheRids(userId);
                Set<String> otherRids = new HashSet<>(rids);
                otherRids.remove(rid);
                Set<String> otherRPairedSource = new HashSet<>();
                if (!CollectionUtils.isEmpty(otherRids)) {
                    if (LocalConstant.DeviceType.T.equalsIgnoreCase(param.getSourceType())) {
                        otherRPairedSource = this.listRsPairTids(otherRids);
                    } else {
                        otherRPairedSource = this.listRsPairedXids(otherRids);
                    }
                }
                existSids.removeAll(otherRPairedSource);
                if (CollectionUtils.isEmpty(existSids)) {
                    log.error("addAndRemoveRPair remove and user other R paired with sids, continue, param:[{}] userId:[{}] otherRPairedSource:[{}] taskId:[{}]", param, userId, otherRPairedSource, taskId);
                    continue;
                }
                for (String existSid : existSids) {
                    log.error("addAndRemoveRPair call removeUserDevice, param:[{}] userId:[{}] existSid:[{}] taskId:[{}]", param, userId, existSid, taskId);
                    this.removeUserDevice(userId, existSid);
                }

                String requestId = distributedGlobalIdUtil.netxId() + "";
            //    List<UserDeviceRecord> userDeviceRecords = new ArrayList<>();
                for (String sid : existSids) {
                    UserDeviceRecord userDeviceRecord = new UserDeviceRecord();
                    userDeviceRecord.setId(distributedGlobalIdUtil.netxId() + "");
                    userDeviceRecord.setCreateTime(System.currentTimeMillis() + "");
                    userDeviceRecord.setRequestId(requestId);
                    userDeviceRecord.setAccount(userId);
                    userDeviceRecord.setUserId(operateUserId);
                    userDeviceRecord.setUserEmail(operateUserEmail);
                    userDeviceRecord.setDeleteFlag(0);
                    userDeviceRecord.setParam("");
                    userDeviceRecord.setOperationType(operationType);
                    userDeviceRecord.setPeerId(sid);
            //        userDeviceRecords.add(userDeviceRecord);
                    userDeviceRecordService.saveRecord(userDeviceRecord);
                }
//                deviceFeignService.saveUserDeviceRecords(userDeviceRecords);
            }
        }
        for (String userId : userIds) {
            this.removeUserCacheDevice(userId);
        }
    }

    private void addAndRemoveSourcePair(AddAndRemoveSourcePairParam param, String operationType, String operateUserId) {
        String sid = param.getSid();
        List<String> rids = param.getRids();
        if (StringUtils.isBlank(sid) || CollectionUtils.isEmpty(rids)) {
            return;
        }
        List<String> sids = new ArrayList<>();
        sids.add(sid);
        for (String rid : rids) {
            AddAndRemoveRPairParam addAndRemoveRPairParam = new AddAndRemoveRPairParam()
                    .setRid(rid)
                    .setSids(sids)
                    .setOperate(param.isOperate())
                    .setSourceType(param.getSourceType());
            this.addAndRemoveRPair(addAndRemoveRPairParam, operationType, operateUserId);
        }
    }

    @Override
    public void notifyDevicePairChange(String message) throws IOException {
        if (!executeNotifyDevicePairChange) {
            return;
        }
        DevicePairDTO dto = JsonUtil.toObject(message, DevicePairDTO.class);
        int operate = dto.getOperate();
        DevicePairData data = dto.getData();
        if (operate == DevicePairDTO.R_ADD_PAIR_WITH_PACKS) {
            AddAndRemoveRPairParam param = new AddAndRemoveRPairParam()
                    .setRid(data.getPeerId())
                    .setOperate(true)
                    .setSourceType(LocalConstant.DeviceType.T)
                    .setSids(data.getRelationPeerIds());
            this.addAndRemoveRPair(param, "TPC add pair", data.getUserId());
        } else if (operate == DevicePairDTO.R_ADD_PAIR_WITH_GRIDS) {
            AddAndRemoveRPairParam param = new AddAndRemoveRPairParam()
                    .setRid(data.getPeerId())
                    .setOperate(true)
                    .setSourceType(LocalConstant.DeviceType.X)
                    .setSids(data.getRelationPeerIds());
            this.addAndRemoveRPair(param, "GCS add pair", data.getUserId());
        } else if (operate == DevicePairDTO.PACK_ADD_PAIR_WITH_RS) {
            AddAndRemoveSourcePairParam param = new AddAndRemoveSourcePairParam()
                    .setSid(data.getPeerId())
                    .setOperate(true)
                    .setSourceType(LocalConstant.DeviceType.T)
                    .setRids(data.getRelationPeerIds());
            this.addAndRemoveSourcePair(param, "TPC add pair", data.getUserId());
        } else if (operate == DevicePairDTO.GRID_ADD_PAIR_WITH_RS) {
            AddAndRemoveSourcePairParam param = new AddAndRemoveSourcePairParam()
                    .setSid(data.getPeerId())
                    .setOperate(true)
                    .setSourceType(LocalConstant.DeviceType.X)
                    .setRids(data.getRelationPeerIds());
            this.addAndRemoveSourcePair(param, "GCS add pair", data.getUserId());
        } else if (operate == DevicePairDTO.R_REMOVE_PAIR_WITH_PACKS) {
            AddAndRemoveRPairParam param = new AddAndRemoveRPairParam()
                    .setRid(data.getPeerId())
                    .setOperate(false)
                    .setSourceType(LocalConstant.DeviceType.T)
                    .setSids(data.getRelationPeerIds());
            this.addAndRemoveRPair(param, "TPC remove pair", data.getUserId());
        } else if (operate == DevicePairDTO.R_REMOVE_PAIR_WITH_GRIDS) {
            AddAndRemoveRPairParam param = new AddAndRemoveRPairParam()
                    .setRid(data.getPeerId())
                    .setOperate(false)
                    .setSourceType(LocalConstant.DeviceType.X)
                    .setSids(data.getRelationPeerIds());
            this.addAndRemoveRPair(param, "GCS remove pair", data.getUserId());
        } else if (operate == DevicePairDTO.PACK_REMOVE_PAIR_WITH_RS) {
            AddAndRemoveSourcePairParam param = new AddAndRemoveSourcePairParam()
                    .setSid(data.getPeerId())
                    .setOperate(false)
                    .setSourceType(LocalConstant.DeviceType.T)
                    .setRids(data.getRelationPeerIds());
            this.addAndRemoveSourcePair(param, "TPC remove pair", data.getUserId());
        } else if (operate == DevicePairDTO.GRID_REMOVE_PAIR_WITH_RS) {
            AddAndRemoveSourcePairParam param = new AddAndRemoveSourcePairParam()
                    .setSid(data.getPeerId())
                    .setOperate(false)
                    .setSourceType(LocalConstant.DeviceType.X)
                    .setRids(data.getRelationPeerIds());
            this.addAndRemoveSourcePair(param, "CGS remove pair", data.getUserId());
        } else if (operate == DevicePairDTO.REMOVE_R_ALL_PAIR) {
            String rid = data.getPeerId();
            Set<String> rids = new HashSet<>();
            rids.add(rid);
            Set<String> tids = this.listRsPairTids(rids);
            if (!CollectionUtils.isEmpty(tids)) {
                AddAndRemoveRPairParam param = new AddAndRemoveRPairParam()
                        .setRid(data.getPeerId())
                        .setOperate(false)
                        .setSourceType(LocalConstant.DeviceType.T)
                        .setSids(new ArrayList<>(tids));
                this.addAndRemoveRPair(param, "TPC move R all pair", data.getUserId());
            }
            Set<String> xids = this.listRsPairedXids(rids);
            if (!CollectionUtils.isEmpty(xids)) {
                AddAndRemoveRPairParam param = new AddAndRemoveRPairParam()
                        .setRid(data.getPeerId())
                        .setOperate(false)
                        .setSourceType(LocalConstant.DeviceType.X)
                        .setSids(new ArrayList<>(xids));
                this.addAndRemoveRPair(param, "TPC move R add pair", data.getUserId());
            }
        } else if (operate == DevicePairDTO.REMOVE_PACK_ALL_PAIR) {
            String tid = data.getPeerId();
            List<String> rids = deviceFeignService.listTPairR(tid);
            if (!CollectionUtils.isEmpty(rids)) {
                AddAndRemoveSourcePairParam param = new AddAndRemoveSourcePairParam()
                        .setSid(tid)
                        .setOperate(false)
                        .setSourceType(LocalConstant.DeviceType.T)
                        .setRids(rids);
                this.addAndRemoveSourcePair(param, "TPC move pack all pair", data.getUserId());
            }
        } else if (operate == DevicePairDTO.REMOVE_GRID_ALL_PAIR) {
            String xid = data.getPeerId();
            List<String> rids = null;
            try {
                rids = gcsManageFeignService.listXPairedR(xid.substring(0, 16), xid.substring(16));
            } catch (Exception e) {
                log.error(e.toString(), e);
                rids = new ArrayList<>();
            }
            if (!CollectionUtils.isEmpty(rids)) {
                AddAndRemoveSourcePairParam param = new AddAndRemoveSourcePairParam()
                        .setSid(xid)
                        .setOperate(false)
                        .setSourceType(LocalConstant.DeviceType.X)
                        .setRids(rids);
                this.addAndRemoveSourcePair(param, "GCS move grid all pair", data.getUserId());
            }
        } else if (operate == DevicePairDTO.COPY_R1_PAIR_TO_R2
                || operate == DevicePairDTO.COPY_PACK1_PAIR_TO_PACK2
                || operate == DevicePairDTO.COPY_GRID1_PAIR_TO_GRID2) {
            // copy 接口不需要做改动，TPC 调用 CC 接口已经完成了
        } else if (operate == DevicePairDTO.MOVE_R1_PAIR_TO_R2
                || operate == DevicePairDTO.MOVE_PACK1_PAIR_TO_PACK2
                || operate == DevicePairDTO.MOVE_GRID1_PAIR_TO_GRID2) {
            // 直接修改 user_device oldPeerId 为 newPeerId，然后删除缓存
            String peerId = data.getPeerId();
            String anotherPeerId = data.getAnotherPeerId();
            if (StringUtils.isBlank(peerId) || StringUtils.isBlank(anotherPeerId)) {
                return;
            }
            UserDevice record = new UserDevice()
                    .setPeerId(peerId);
            List<UserDevice> userDevices = userDeviceMapper.select(record);
            if (!CollectionUtils.isEmpty(userDevices)) {
                for (UserDevice userDevice : userDevices) {
                    userDevice.setPeerId(anotherPeerId);
                    userDeviceMapper.updateByPrimaryKey(userDevice);
                }
                Set<String> userIds = userDevices.stream().map(i -> i.getUserId()).collect(Collectors.toSet());
                for (String userId : userIds) {
                    this.removeUserCacheDevice(userId);
                }
            }
        } else {
            log.error("notifyDevicePairChange error operate:{}", message);
        }
    }

    private Set<String> listRPairedSource(String rid) {
        List<String> rids = new ArrayList<>();
        rids.add(rid);
        return this.listRPairedSource(rids);
    }

    private Set<String> listRPairedSource(Collection<String> rids) {
        if (CollectionUtils.isEmpty(rids)) {
            return new HashSet<>();
        }
        HashSet<String> peerIds = new HashSet<>(rids);
        Set<String> pairedPeerIds = new HashSet<>();
        Set<String> tids = this.listRsPairTids(peerIds);
        if (!CollectionUtils.isEmpty(tids)) {
            pairedPeerIds.addAll(tids);
        }
        Set<String> xids = this.listRsPairedXids(peerIds);
        if (!CollectionUtils.isEmpty(xids)) {
            pairedPeerIds.addAll(xids);
        }
        return pairedPeerIds;
    }

    @Override
    public void reloadUser(LoginUser loginUser, ReloadUserParam param) {
        List<String> userIds = param.getUserIds();
        if (CollectionUtils.isEmpty(userIds)) {
            return;
        }
        for (String userId : userIds) {
            User user = userService.getById(userId);
            if (user == null) {
                log.error("UserDevice reloadUser failed, user is null, userId:[{}]", userId);
                continue;
            }

            boolean userExistFeature = userFeatureService.isUserExistFeatureName(userId, disableReceiverCentricFeature);
            if (userExistFeature) {
                log.error("reloadUser user exist disableReceiverCentricFeature Feature return, userId:[{}]", userId);
                continue;
            }

            List<String> rids = this.listUserCacheRids(userId);

            // 用户 R 配对的所有 Source
            Set<String> pairedSources = new HashSet<>();
            if (!CollectionUtils.isEmpty(rids)) {
                pairedSources = this.listRPairedSource(rids);

                for (String rid : rids) {
                    List<String> gridIds = userDeviceMapper.listGridPeerIds(rid);
                    if (!CollectionUtils.isEmpty(gridIds)) {
                        pairedSources.addAll(gridIds);
                    }
                }
            }

            // 用户已绑定的所有 Source
            List<String> bindedSources = this.listUserCacheDeviceIds(userId);
            bindedSources.removeAll(rids);

            if (param.isAdd()) {
                Set<String> addPeerIds = new HashSet<>(pairedSources);
                addPeerIds.removeAll(bindedSources);

                if (!CollectionUtils.isEmpty(addPeerIds)) {
                    this.addUserDevices(userId, addPeerIds, user.getRole());

                    String requestId = MyUtil.getUUID();
                    for (String peerId : addPeerIds) {
                        UserDeviceRecord userDeviceRecord = new UserDeviceRecord();
                        userDeviceRecord.setId(distributedGlobalIdUtil.netxId() + "");
                        userDeviceRecord.setCreateTime(System.currentTimeMillis() + "");
                        userDeviceRecord.setRequestId(requestId);
                        userDeviceRecord.setAccount(userId);
                        userDeviceRecord.setUserId(loginUser.getId());
                        userDeviceRecord.setUserEmail(loginUser.getEmail());
                        userDeviceRecord.setDeleteFlag(0);
                        userDeviceRecord.setParam("");
                        userDeviceRecord.setOperationType("Reload User Add Pair");
                        userDeviceRecord.setPeerId(peerId);
                        userDeviceRecordService.saveRecord(userDeviceRecord);
                    }
                }
            }

            if (param.isRemove()) {
                List<String> removePeerIds = new ArrayList<>(bindedSources);
                removePeerIds.removeAll(pairedSources);

                if (!CollectionUtils.isEmpty(removePeerIds)) {
                    for (String peerId : removePeerIds) {
                        this.removeUserDevice(userId, peerId);
                    }

                    String requestId = MyUtil.getUUID();
                    for (String peerId : removePeerIds) {
                        UserDeviceRecord userDeviceRecord = new UserDeviceRecord();
                        userDeviceRecord.setId(distributedGlobalIdUtil.netxId() + "");
                        userDeviceRecord.setCreateTime(System.currentTimeMillis() + "");
                        userDeviceRecord.setRequestId(requestId);
                        userDeviceRecord.setAccount(userId);
                        userDeviceRecord.setUserId(loginUser.getId());
                        userDeviceRecord.setUserEmail(loginUser.getEmail());
                        userDeviceRecord.setDeleteFlag(0);
                        userDeviceRecord.setParam("");
                        userDeviceRecord.setOperationType("Reload User Remove Pair");
                        userDeviceRecord.setPeerId(peerId);
                        userDeviceRecordService.saveRecord(userDeviceRecord);
                    }
                }
            }


            this.removeUserCacheDevice(userId);
        }
    }

    @Override
    public void reloadReceiver(LoginUser loginUser, List<String> rids) {
        if (CollectionUtils.isEmpty(rids)) {
            return;
        }
        for (String rid : rids) {
            Device device = deviceService.getCurrentDevice(rid);
            if (device == null) {
                continue;
            }
            if (!LocalConstant.DeviceType.R.equalsIgnoreCase(device.getType())) {
                continue;
            }
            List<String> userIds = this.listCacheDeviceBelongUser(rid);
            if (CollectionUtils.isEmpty(userIds)) {
                continue;
            }
            Set<String> pairedSource = this.listRPairedSource(rid);
            if (CollectionUtils.isEmpty(pairedSource)) {
                continue;
            }
            for (String userId : userIds) {
                User user = userService.getById(userId);
                if (user == null) {
                    log.error("UserDevice reloadReceiver failed, user is null, userId:[{}] rids:[{}]", userId, rids);
                    continue;
                }

                boolean userExistFeature = userFeatureService.isUserExistFeatureName(userId, disableReceiverCentricFeature);
                if (userExistFeature) {
                    log.error("reloadReceiver user exist disableReceiverCentricFeature Feature return, userId:[{}] rids:[{}]", userId, rids);
                    continue;
                }

                Set<String> pairedList = new HashSet<>(pairedSource);
                List<String> userBindPeerIds = this.listUserCacheDeviceIds(userId);
                pairedList.removeAll(userBindPeerIds);
                if (CollectionUtils.isEmpty(pairedList)) {
                    continue;
                }

                this.addUserDevices(userId, pairedList, user.getRole());

                String requestId = MyUtil.getUUID();
                for (String peerId : pairedList) {
                    UserDeviceRecord userDeviceRecord = new UserDeviceRecord();
                    userDeviceRecord.setId(distributedGlobalIdUtil.netxId() + "");
                    userDeviceRecord.setCreateTime(System.currentTimeMillis() + "");
                    userDeviceRecord.setRequestId(requestId);
                    userDeviceRecord.setAccount(userId);
                    userDeviceRecord.setUserId(loginUser.getId());
                    userDeviceRecord.setUserEmail(loginUser.getEmail());
                    userDeviceRecord.setDeleteFlag(0);
                    userDeviceRecord.setParam("");
                    userDeviceRecord.setOperationType("Reload Receiver Add Pair");
                    userDeviceRecord.setPeerId(peerId);
                    userDeviceRecordService.saveRecord(userDeviceRecord);
                }

                this.removeUserCacheDevice(userId);
            }

        }
    }

    @Override
    public PageInfo<SearchUserDeviceVo> pageUserRPairedSource(PageUserRPairedSourceParam param) {
        String rid = param.getRid();
        Set<String> rids = new HashSet<>();
        rids.add(rid);
        Set<String> sids = new HashSet<>();
        Set<String> tids = this.listRsPairTids(rids);
        sids.addAll(tids);
        Set<String> xids = this.listRsPairedXids(rids);
        sids.addAll(xids);

        if (!param.isCorrelate()) {
            List<String> userRids = this.listUserDeviceIds(param.getUserId());
            sids.retainAll(userRids);
        }
        List<String> tokenAnywhereIds = this.getTokenAnywhereIds(param.getUserId(), rid, Boolean.FALSE, null, Boolean.TRUE);
        //根据用户下的tokenAnywhereIds ,去查询该Anywhere是否有授权owner.
        Set<String> ownerAnywhere = tokenFeignService.listTokenAnywhereOwner(tokenAnywhereIds,true);
        if(!CollectionUtils.isEmpty(ownerAnywhere)){
            tokenAnywhereIds.removeAll(ownerAnywhere);
        }
        if (!CollectionUtils.isEmpty(tokenAnywhereIds)) {
            sids.addAll(tokenAnywhereIds);
        }
        if (CollectionUtils.isEmpty(sids)) {
            return new PageInfo<>(new ArrayList<>());
        }
        List<SearchUserDeviceVo> list = new ArrayList<>();
        for (String sid : sids) {
            Device device = deviceService.getCurrentDevice(sid);
            if (device != null) {
                SearchUserDeviceVo searchUserDeviceVo = new SearchUserDeviceVo();
                BeanUtils.copyProperties(device, searchUserDeviceVo);
                boolean userOwner = userDeviceService.isUserOwner(param.getUserId(), sid);
                if (userOwner) {
                    searchUserDeviceVo.setRelation(1);
                } else {
                    searchUserDeviceVo.setRelation(0);
                }
                list.add(searchUserDeviceVo);
            }

        }
        //给owner的anyWhere设置回显值  setRelation
        for (String s : ownerAnywhere) {
            Device device = deviceService.getCurrentDevice(s);
            if (device != null) {
                SearchUserDeviceVo searchUserDeviceVo = new SearchUserDeviceVo();
                BeanUtils.copyProperties(device, searchUserDeviceVo);
                searchUserDeviceVo.setRelation(1);
                list.add(searchUserDeviceVo);
            }
        }
        if (CollectionUtils.isEmpty(list)) {
            return new PageInfo<>(new ArrayList<>());
        }
        PageInfo<SearchUserDeviceVo> pageInfo = MyUtil.packagePageInfo(list, param.getPageNum(), param.getPageSize());
        return pageInfo;
    }

    @Override
    public void resetOwner() {
        List<Map<String, String>> list = userDeviceMapper.listOwner();
        if (CollectionUtils.isEmpty(list)) {
            return;
        }
        for (Map<String, String> map : list) {
            String peerId = map.get("peerId");
            String userId = map.get("userId");
            UserDevice record = new UserDevice()
                    .setUserId(userId)
                    .setPeerId(peerId);
            List<UserDevice> existList = userDeviceMapper.select(record);
            if (CollectionUtils.isEmpty(existList)) {
                continue;
            }
            for (UserDevice userDevice : existList) {
                if (userDevice.getRelation() == 1) {
                    continue;
                }
                userDevice.setRelation(1);
                userDeviceMapper.updateByPrimaryKeySelective(userDevice);
            }
        }
    }

    @Override
    public List<RExtRelation> listNeedResetRExt() {
        return resetRExt2();
    }

    @Override
    public void resetRExt(List<RExtRelation> list) {
        if (CollectionUtils.isEmpty(list)) {
            return;
        }
        List<String> ids = list.stream().map(i -> i.getId()).collect(Collectors.toList());
        userDeviceMapper.deleteRExtRelation(ids);

    }

    @Override
    public List<SearchUserDeviceVo> getReceiverListByUserId(String userId, String condition) {
        SearchUserDeviceParam param = new SearchUserDeviceParam();
        param.setUserId(userId)
                .setReceiver(true);
        param.setCondition(condition);
        String appendSql = param.appendTypeSql();
        param.setAppendSql(appendSql);
        return userDeviceMapper.listSettingPageUserBindDevice(param);
    }

    @Override
    public String bingUserPackAndAnywhere(String userId, String operationUserId, List<String> addPeerIds, List<String> removePeerIds, String serviceName) {
        String addPeerIdString = "";
        String removePeerIdString = "";
        if (!CollectionUtils.isEmpty(addPeerIds)) {
            List<Device> devices = deviceService.listCurrentDevice(addPeerIds);
            if (!CollectionUtils.isEmpty(devices)) {
                addPeerIdString = Joiner.on(",").join(devices.stream().filter(s -> "T".equalsIgnoreCase(s.getType()))
                        .map(Device::getPeerId).collect(Collectors.toSet()));
            }
        }
        if (!CollectionUtils.isEmpty(removePeerIds)) {
            List<Device> devices = deviceService.listCurrentDevice(removePeerIds);
            if (!CollectionUtils.isEmpty(devices)) {
                removePeerIdString = Joiner.on(",").join(devices.stream().filter(s -> "T".equalsIgnoreCase(s.getType()))
                        .map(Device::getPeerId).collect(Collectors.toSet()));
            }
        }
        User user = userService.getById(userId);
        if (user == null) {
            return "User not exist";
        }
        String role = user.getRole();
        if (!(LocalConstant.UserRole.ADMIN.equals(role) || LocalConstant.UserRole.USER.equals(role))) {
            return "User is not admin role or user role";
        }
        User operationUser = userService.getById(operationUserId);
        String email = "";
        if (operationUser != null) {
            email = operationUser.getEmail();
        }
        if (StringUtils.isNotEmpty(addPeerIdString) || StringUtils.isNotEmpty(removePeerIdString)) {
            this.correlateUserDevice(userId, addPeerIdString, removePeerIdString, null, null, operationUserId);
            roleUserService.deleteByUserId(userId);
        }
        if (StringUtils.isNotEmpty(addPeerIdString)) {
            Map map = new HashMap();
            map.put("peerIdList", addPeerIdString);
            map.put("userIdList", userId);
            String remark = serviceName + "_AddUserDeviceRelation";
            this.saveUserDeviceRecord(email, operationUserId, remark, map);
        }
        if (StringUtils.isNotEmpty(removePeerIdString)) {
            Map map = new HashMap();
            map.put("peerIdList", removePeerIds);
            map.put("userIdList", userId);
            String remark = serviceName + "_RemoveUserDeviceRelation";
            this.saveUserDeviceRecord(email, operationUserId, remark, map);
        }
        return null;
    }

    @Override
    public String bindUserReceiverCenter(String operationUserId, List<String> bindPeerIds, List<String> userIds) {
        //1.校验
        if (CollectionUtils.isEmpty(bindPeerIds) || CollectionUtils.isEmpty(userIds)) {
            return "";
        }
        User operationUser = userService.getById(operationUserId);
        if (operationUser == null) {
            return "OperationUser not exist";
        }
        List<String> peerIds = deviceService.checkDeviceType(bindPeerIds, LocalConstant.DeviceType.R);
        if (CollectionUtils.isEmpty(peerIds)) {
            log.error("bindUserReceiverCenter>>>peerId not exist or type not R,peerIds", bindPeerIds);
        }
        List<String> sourceIds = new ArrayList<>();
        try {
            List<String> strings = this.listReceiversGrid(peerIds);
            if (!CollectionUtils.isEmpty(strings)) {
                sourceIds.addAll(strings);
            }
        } catch (Exception e) {
            log.error("bindUserReceiverCenter>>>get peerId source exception,peerIds:[{}],exception:[{}]", peerIds, e);
            return "user device feign exception!";
        }
        final CountDownLatch countDownLatch = new CountDownLatch(userIds.size());
        userIds.forEach(s -> {
            UserThreadPool.SERVICETHREADPOOL.execute(() -> {
                try {
                    //1.校验用户是否存在
                    User user = userService.getById(s);
                    if (user == null || !(LocalConstant.UserRole.ADMIN.equals(user.getRole())
                            || LocalConstant.UserRole.USER.equals(user.getRole()))) {
                        log.error("bindUserReceiverCenter>>>user not exist or user is not admin or user role,userId:[{}]", s);
                        return;
                    }
                    List<String> existReceiverIds = this.listUserCacheRids(s);
                    Set<String> addPeerIds = new HashSet<>(peerIds);
                    if (!CollectionUtils.isEmpty(existReceiverIds)) {
                        addPeerIds.removeAll(existReceiverIds);
                    }
                    if (CollectionUtils.isEmpty(addPeerIds)) {
                        log.error("bindUserReceiverCenter>>>user already bind all receiver,userId:[{}],peerIds:[{}]", s, peerIds);
                        return;
                    }
                    if (addPeerIds.size() != peerIds.size()) {
                        log.error("bindUserReceiverCenter>>>user already bind this receiver,userId:[{}],needAddR:[{}],peerIds:[{}]",
                                s, addPeerIds, peerIds);
                    }
                    //获取所有的R、T、X
                    Set<String> tPeerIds = this.listRsPairTids(addPeerIds);
                    Set<String> xPeerIds = this.listRsPairedXids(addPeerIds);
                    if (!CollectionUtils.isEmpty(tPeerIds)) {
                        addPeerIds.addAll(tPeerIds);
                    }
                    if (!CollectionUtils.isEmpty(xPeerIds)) {
                        addPeerIds.addAll(xPeerIds);
                    }
                    if (!CollectionUtils.isEmpty(sourceIds)) {
                        addPeerIds.addAll(sourceIds);
                    }
                    List<String> existDeviceIds = this.listUserCacheDeviceIds(s);
                    if (!CollectionUtils.isEmpty(existDeviceIds)) {
                        addPeerIds.removeAll(existDeviceIds);
                        if (CollectionUtils.isEmpty(addPeerIds)) {
                            log.error("bindUserReceiverCenter>>>user need not bind device,userId:[{}]", s);
                            return;
                        }
                    }
                    this.addUserDevices(s, addPeerIds, user.getRole());
                    this.removeUserCacheDevice(s);
                    //用户行为记录
                    Map map = new HashMap();
                    map.put("peerIdList", addPeerIds);
                    map.put("userIdList", s);
                    String remark = "Account_AddUserDeviceRelation";
                    this.saveUserDeviceRecord(operationUser.getEmail(), operationUserId, remark, map);
                } catch (Exception e) {
                    log.error("bindUserReceiverCenter>>> user bind exception,userId:[{}]", s, e);
                } finally {
                    countDownLatch.countDown();
                }
            });
        });
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            countDownLatch.countDown();
            log.error(e.toString(), e);
        }
        return null;
    }

    /**
     * 获取R下所有的grid
     *
     * @param receiverList
     * @return
     */
    private List<String> listReceiversGrid(List<String> receiverList) {
        List<String> sourceIds = new ArrayList<>();
        Map<String, List<Device>> sourceMap = deviceFeignService.listReceiversGrid(receiverList);
        if (sourceMap != null && sourceMap.size() > 0) {
            sourceMap.values().forEach(s -> {
                if (!CollectionUtils.isEmpty(s)) {
                    List<String> collect = s.stream().map(Device::getPeerId).collect(Collectors.toList());
                    if (!CollectionUtils.isEmpty(collect)) {
                        sourceIds.addAll(collect);
                    }
                }
            });
        }
        return sourceIds;
    }

    @Override
    public String unbindUserReceiverCenter(String operationUserId, List<String> unbindPeerIds, List<String> userIds) {

        if (CollectionUtils.isEmpty(unbindPeerIds) || CollectionUtils.isEmpty(userIds)) {
            return "";
        }
        List<String> peerIds = unbindPeerIds.stream().map(String::toLowerCase).collect(Collectors.toList());
        User operationUser = userService.getById(operationUserId);
        if (operationUser == null) {
            return "Operation User not exist!";
        }
        List<String> sourceIds = new ArrayList<>();
        try {
            List<String> strings = this.listReceiversGrid(peerIds);
            if (!CollectionUtils.isEmpty(strings)) {
                sourceIds.addAll(strings);
            }
        } catch (Exception e) {
            log.error("unbindUserReceiverCenter>>>get peerId source exception,peerIds:[{}],exception:[{}]", peerIds, e);
            return "user device feign exception!";
        }
        final CountDownLatch countDownLatch = new CountDownLatch(userIds.size());
        userIds.forEach(s -> {
            UserThreadPool.SERVICETHREADPOOL.execute(() -> {
                try {
                    //1.校验用户是否存在
                    User user = userService.getById(s);
                    if (user == null || !(LocalConstant.UserRole.ADMIN.equals(user.getRole())
                            || LocalConstant.UserRole.USER.equals(user.getRole()))) {
                        log.error("unbindUserReceiverCenter>>>user not exist or user is not admin or user role,userId:[{}]", s);
                        return;
                    }
                    //2.校验用户是否有Receiver
                    List<String> existReceiverIds = this.listUserCacheRids(s);
                    if (CollectionUtils.isEmpty(existReceiverIds)) {
                        log.error("unbindUserReceiverCenter>>>user not bind receiver,need not delete,userId:[{}]", s);
                        return;
                    }
                    List<String> removePeerIds = peerIds.stream().filter(existReceiverIds::contains).collect(Collectors.toList());
                    if (CollectionUtils.isEmpty(removePeerIds)) {
                        log.error("unbindUserReceiverCenter>>>user not bind need delete receiver,so need not delete,userId:[{}]", s);
                        return;
                    }
                    if (removePeerIds.size() != peerIds.size()) {
                        log.error("unbindUserReceiverCenter>>>user not bind need delete receiver,so need not delete this r" +
                                ",userId:[{}],needDeleteR:[{}],peerIds:[{}]", s, removePeerIds, peerIds);
                    }
                    existReceiverIds.removeAll(peerIds);
                    //3.去除用户没有的peerId
                    List<String> canNotDeleteSourceIdsAndPackIds = new ArrayList<>();
                    if (!CollectionUtils.isEmpty(existReceiverIds)) {
                        Set<String> existReceiverIdSet = new HashSet<>(existReceiverIds);
                        Set<String> tPeerIds = this.listRsPairTids(existReceiverIdSet);
                        Set<String> xPeerIds = this.listRsPairedXids(existReceiverIdSet);
                        if (!CollectionUtils.isEmpty(tPeerIds)) {
                            canNotDeleteSourceIdsAndPackIds.addAll(tPeerIds);
                        }
                        if (!CollectionUtils.isEmpty(xPeerIds)) {
                            canNotDeleteSourceIdsAndPackIds.addAll(xPeerIds);
                        }
                    }
                    Set<String> peerIdSet = new HashSet<>(removePeerIds);
                    Set<String> removeTPeerIds = this.listRsPairTids(peerIdSet);
                    Set<String> removeXPeerIds = this.listRsPairedXids(peerIdSet);
                    if (!CollectionUtils.isEmpty(removeTPeerIds)) {
                        removePeerIds.addAll(removeTPeerIds);
                    }
                    if (!CollectionUtils.isEmpty(removeXPeerIds)) {
                        removePeerIds.addAll(removeXPeerIds);
                    }
                    if (!CollectionUtils.isEmpty(sourceIds)) {
                        removePeerIds.addAll(sourceIds);
                    }
                    if (!CollectionUtils.isEmpty(canNotDeleteSourceIdsAndPackIds)) {
                        removePeerIds.removeAll(canNotDeleteSourceIdsAndPackIds);
                    }
                    //删除所有的R、T、X
                    List<String> existPeerIds = this.listUserCacheDeviceIds(s);
                    if (CollectionUtils.isEmpty(existPeerIds)) {
                        log.error("unbindUserReceiverCenter>>>user have not device,userId:[{}]", s);
                        return;
                    }
                    removePeerIds = removePeerIds.stream().filter(existPeerIds::contains).collect(Collectors.toList());
                    if (CollectionUtils.isEmpty(removePeerIds)) {
                        log.error("unbindUserReceiverCenter>>>user need not delete device,userId:[{}]", s);
                        return;
                    }
                    List<String> willRemoveUserIds = new ArrayList<>();
                    willRemoveUserIds.add(s);
                    List<String> userDeviceIds = userDeviceMapper.listIdInUsersAndPeerIds(willRemoveUserIds, removePeerIds);
                    userDeviceMapper.deleteByIdList(userDeviceIds);
                    this.removeUserCacheDevice(s);
                    //用户行为记录
                    Map map = new HashMap();
                    map.put("peerIdList", removePeerIds);
                    map.put("userIdList", s);
                    String remark = "Account_RemoveUserDeviceRelation";
                    this.saveUserDeviceRecord(operationUser.getEmail(), operationUserId, remark, map);
                } finally {
                    countDownLatch.countDown();
                }
            });
        });
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            countDownLatch.countDown();
            log.error(e.toString(), e);
        }
        return "";
    }

    @Override
    public PageInfo<Device> pageRPairedSource(PageUserUnbindRPairedSourceParam param) {
        String rid = param.getRid();
        Set<String> rids = new HashSet<>();
        rids.add(rid);
        Set<String> sids = new HashSet<>();
        Set<String> tids = this.listRsPairTids(rids);
        if (!CollectionUtils.isEmpty(tids)) {
            sids.addAll(tids);
        }
        Set<String> xids = this.listRsPairedXids(rids);
        if (!CollectionUtils.isEmpty(xids)) {
            sids.addAll(xids);
        }
        Set<String> tokenIds = tokenFeignService.listRsPairedTids(rids);
        if (!CollectionUtils.isEmpty(tokenIds)) {
            sids.addAll(tokenIds);
        }
        if (CollectionUtils.isEmpty(sids)) {
            return new PageInfo<>(new ArrayList<>());
        }
        List<Device> devices = deviceService.listCurrentDevice(sids);
        if (CollectionUtils.isEmpty(devices)) {
            return new PageInfo<>(new ArrayList<>());
        }
        return MyUtil.packagePageInfo(devices, param.getPageNum(), param.getPageSize());
    }

    @Override
    public PageInfo<FeatureDeviceVo> pageAllUserRWithGlobalGridFeature(String userId, SearchSourcePairedRParam param) {
        PageHelper.startPage(param.getPageNum(), param.getPageSize());
        String condition = param.getCondition();
        condition = MyUtil.formatCondition(condition);
        List<SimpleDeviceVo> devices = userDeviceMapper.listUserSimpleDevice(userId, condition, LocalConstant.DeviceType.R);
        if (CollectionUtils.isEmpty(devices)) {
            return new PageInfo<>();
        }
        List<String> receivers = devices.stream().map(SimpleDeviceVo::getPeerId).collect(Collectors.toList());
        FeatureStatusInfo featureStatusInfo = new FeatureStatusInfo()
                .setFeatureName(globalGridFeature)
                .setType(LocalConstant.DeviceType.R)
                .setPeerIdList(receivers);
        Result<FeatureStatusInfo> result = newTpcFeignService.getFeatureStatusInfo(featureStatusInfo);
        List<String> existGlobalGridFeaturePeerIds = new ArrayList<>();
        if (result == null || !result.assertSuccess()) {
            log.error("pageAllUserRWithGlobalGridFeature>>>>>>call tpc feign service is error,userId:[{}],receivers:[{}],result:[{}]"
                    , userId, receivers, result);
        } else {
            FeatureStatusInfo featureStatus = result.getResult();
            Map<String, FeatureInfo> peerFeatureMap = featureStatus.getPeerFeatureMap();
            if (peerFeatureMap != null && peerFeatureMap.size() > 0) {
                existGlobalGridFeaturePeerIds.addAll(peerFeatureMap.keySet().stream()
                        .filter(s -> StringUtils.equals("0001", peerFeatureMap.get(s).getParaType()))
                        .collect(Collectors.toList()));
            }
        }
        List<FeatureDeviceVo> featureDeviceVos = new ArrayList<>();
        devices.forEach(s -> {
            FeatureDeviceVo featureDeviceVo = new FeatureDeviceVo()
                    .setName(s.getName())
                    .setPeerId(s.getPeerId())
                    .setGlobalGridFeature(existGlobalGridFeaturePeerIds.contains(s.getPeerId()));
            featureDeviceVos.add(featureDeviceVo);
        });
        PageInfo<FeatureDeviceVo> featureDeviceVoPageInfo = new PageInfo<>(featureDeviceVos);
        featureDeviceVoPageInfo.setTotal(devices.size());
        return featureDeviceVoPageInfo;
    }

    /**
     *
     * @return List
     */
    public List<RExtRelation> resetRExt1() {
        List<RExtRelation> resultList = new ArrayList<>();
        List<String> rids = userDeviceMapper.listExternalRRelationR();
        if (CollectionUtils.isEmpty(rids)) {
            return new ArrayList<>();
        }
        for (String rid : rids) {
            List<String> peerIds = new ArrayList<>();
            List<String> userIds = this.listCacheDeviceBelongUser(rid);
            if (!CollectionUtils.isEmpty(userIds)) {
                for (String userId : userIds) {
                    List<String> pids = this.listUserCacheDeviceIds(userId);
                    peerIds.addAll(pids);
                }
            }

            List<RExtRelation> allList = userDeviceMapper.listRExtRelationByRid(rid);
            if (CollectionUtils.isEmpty(allList)) {
                continue;
            }

            List<RExtRelation> list = allList.stream().filter(i -> !peerIds.contains(i.getFullId())).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(list)) {
                continue;
            }
            resultList.addAll(list);
        }

        return resultList;
    }

    /**
     *
     * @return List
     */
    public List<RExtRelation> resetRExt2() {
        List<RExtRelation> resultList = new ArrayList<>();
        List<String> rids = userDeviceMapper.listExternalRRelationR();
        if (CollectionUtils.isEmpty(rids)) {
            return new ArrayList<>();
        }
        for (String rid : rids) {
            List<RExtRelation> list = userDeviceMapper.listRNeedRemoveRelation(rid);
            resultList.addAll(list);
        }
        return resultList;
    }

    /**
     * 根据Rid 查出配对的Pack
     * @param rids rids
     * @return 集合
     */
    public Set<String> listRsPairTids(Set<String> rids) {
        try {
            Result<Set<String>> result = newTpcFeignService.getTListPairedByRIds(rids);
            if (result.assertSuccess()) {
                return result.getResult();
            }
            return new HashSet<>();
        } catch (Exception e) {
            log.error(e.toString(), e);
            return new HashSet<>(0);
        }
    }

    /**
     * 根据Rid,查出衍生的X
     * @param rids rids
     * @return 集合
     */
    public Set<String> listRsPairedXids(Set<String> rids) {
        try {
            Set<String> xids = gcsManageFeignService.listRsPairedXids(rids);
            if (xids == null) {
                return new HashSet<>();
            }
            return xids;
        } catch (Exception e) {
            log.error(e.toString(), e);
            return new HashSet<>(0);
        }
    }

    private void removeReceiverTokenPair(String userId, Collection<String> peerIds) {
        List<String> rids = userDeviceMapper.filterReceiver(peerIds);
        if (CollectionUtils.isEmpty(rids)) {
            return;
        }
        log.error("removeReceiverTokenPair userId:[{}] peerIds:[{}]", userId, peerIds);
        // lebron
        UserThreadPool.SERVICETHREADPOOL.execute(() -> {
            RemovePairDto param = new RemovePairDto();
            param.setUserId(userId);
            param.setRids(rids);
            try {
                Result<Object> result = tokenFeignService.removePairByUserIdAndRid(param);
                log.error("removeReceiverTokenPair call tvucc-token removePairByUserIdAndRid success param:[{}] result:[{}]", param, result);
            } catch (Exception e) {
                log.error("removeReceiverTokenPair call tvucc-token removePairByUserIdAndRid exception param:[{}] e:[{}]", param, e.toString());
                log.error(e.toString(), e);
            }

        });
    }

    private void removeUserRExtRelation(String userId, Collection<String> rids) {
        if (StringUtils.isBlank(userId) || CollectionUtils.isEmpty(rids)) {
            return;
        }
        log.error("removeUserRExtRelation userId:[{}] peerIds:[{}]", userId, rids);
        UserThreadPool.SERVICETHREADPOOL.execute(() -> {
            List<RExtRelation> list = userDeviceMapper.listNeedRemoveRelation(userId, rids);
            if (CollectionUtils.isEmpty(list)) {
                return;
            }
            Map<String, String> receiverLivePeerIdMap = new HashMap<>();
            Set<String> effectRids = list.stream().map(RExtRelation::getRid).collect(Collectors.toSet());
            if (!CollectionUtils.isEmpty(effectRids)) {
                for (String rid : effectRids) {
                    Device receiver = deviceService.getCurrentDevice(rid);
                    if (receiver != null && StringUtils.isNotBlank(receiver.getLivePeerId())) {
                        receiverLivePeerIdMap.put(rid, receiver.getLivePeerId());
                    }
                }
            }
            // R 正在 live 的 ext peerId 不能移除
            List<String> ids = list.stream().filter(i -> !i.getFullId().equalsIgnoreCase(receiverLivePeerIdMap.get(i.getRid()))).map(RExtRelation::getId).collect(Collectors.toList());
            userDeviceMapper.deleteRExtRelation(ids);
            for (String rid : effectRids) {
                deviceFeignService.preloadExtXToR(rid);
            }
        });
    }


    @Override
    public Result<PageInfo<PageInfoBookMarkParam>> pageInfoBookMark(String userId, PageInfoBookMarkParam pageInfoBookMarkParam) {
        Integer pageNum = pageInfoBookMarkParam.getPageNum();
        Integer pageSize = pageInfoBookMarkParam.getPageSize();

        PageHelper.startPage(pageNum, pageSize);

        String search = pageInfoBookMarkParam.getSearch();
        String parentId = pageInfoBookMarkParam.getParentId();

        List<PageInfoBookMarkParam> pageInfoBookMarkParamList = userDeviceMapper.pageInfoBookMark(userId, parentId, search);

        return ResultUtil.success(new PageInfo(pageInfoBookMarkParamList));
    }


    @Override
    public List<String> selectRByBookmarkId(String bookmarkId) throws Exception {
        return userDeviceMapper.selectRByBookmarkId(bookmarkId);
    }

    @Override
    public Result startAllByBookMarkId(PageInfoRByBookMarkParam param) throws Exception {
        String bookmarkId = param.getBookmarkId();
        String sourceId = param.getSourceId();

        StartAndStopRListVo startRListVo = new StartAndStopRListVo();
        List<StartAllByRBookmarkIdVo> successList = new ArrayList<>();
        List<StartAllByRBookmarkIdVo> errorList = new ArrayList<>();
        List<String> list = selectRByBookmarkId(bookmarkId);
        if (list.size() != 0) {
            for (String s : list) {
                Device device = deviceFeignService.getCurrentDevice(s);
                if (device != null) {
                    StartAllByRBookmarkIdVo vo = new StartAllByRBookmarkIdVo();
                    if ("1".equals(device.getStatus())) {
                        String rid = device.getPeerId();
                        Result<String> stringResult = deviceFeignService.startLive(rid, sourceId);
                        String errorInfo = stringResult.getErrorInfo();
                        String errorCode = stringResult.getErrorCode();
                        if (stringResult.getErrorCode().equals("0x0")) {
                            vo.setName(device.getName());
                            vo.setPeerId(device.getPeerId());
                            vo.setErrorCode(errorCode);
                            vo.setErrorInfo(errorInfo);
                            successList.add(vo);
                            startRListVo.setSuccessList(successList);
                        } else {
                            vo.setName(device.getName());
                            vo.setPeerId(device.getPeerId());
                            vo.setErrorCode(errorCode);
                            vo.setErrorInfo(errorInfo);
                            errorList.add(vo);
                            startRListVo.setErrorList(errorList);
                        }
                    } else if ("2".equals(device.getStatus())) {
                        String rid = device.getPeerId();
                        String sourceIdR = device.getLivePeerId();
                        Result<String> stringResult = deviceFeignService.stopLive(rid, sourceIdR);
                        String errorInfo = stringResult.getErrorInfo();
                        String errorCode = stringResult.getErrorCode();
                        if (!stringResult.getErrorCode().equals("0x0")) {
                            vo.setName(device.getName());
                            vo.setPeerId(device.getPeerId());
                            vo.setErrorCode(errorCode);
                            vo.setErrorInfo(errorInfo);
                            errorList.add(vo);
                            startRListVo.setErrorList(errorList);
                            continue;
                        }
                        Result<String> stringResult1 = deviceFeignService.startLive(rid, sourceId);
                        String errorCode1 = stringResult1.getErrorCode();
                        String errorInfo1 = stringResult1.getErrorInfo();

                        if (stringResult1.getErrorCode().equals("0x0")) {
                            vo.setName(device.getName());
                            vo.setPeerId(device.getPeerId());
                            vo.setErrorCode(errorCode1);
                            vo.setErrorInfo(errorInfo1);
                            successList.add(vo);
                            startRListVo.setSuccessList(successList);
                        } else {
                            vo.setName(device.getName());
                            vo.setPeerId(device.getPeerId());
                            vo.setErrorCode(errorCode);
                            vo.setErrorInfo(errorInfo);
                            errorList.add(vo);
                            startRListVo.setErrorList(errorList);
                        }
                    }
                }
            }
        } else {
            return ResultUtil.error("81100101", "Receiver not exist", null);
        }
        return ResultUtil.success(startRListVo);
    }


    @Override
    public Result<PageInfo<Device>> pageInfoRByBookMark(String userId, String bookmarkId, List<String> status, String search, Integer pageSize, Integer pageNum) {

        //查询不在bookmark文件夹下的R
        if (bookmarkId.equals("Other")) {
            List<Device> devices = userDeviceMapper.pageInfoRNoBookMark(userId, search);
            List<Device> lists = new ArrayList<>();
            return getResult(status, pageSize, pageNum, devices, lists);
        }

        List<Device> lists = new ArrayList<>();
        List<Device> devices = userDeviceMapper.pageInfoRByBookMark(bookmarkId, search);

        return getResult(status, pageSize, pageNum, devices, lists);
    }

    private Result getResult(List<String> statusR, Integer pageSize, Integer pageNum, List<Device> devices, List<Device> lists) {
        if (devices.size() != 0) {
            for (Device device : devices) {
                String peerId = device.getPeerId();
                Device status = deviceFeignService.getCurrentDevice(peerId);
                // todo listMemDevice
                device.setStatus(status.getStatus());
                for (String s : statusR) {
                    if (s.equals(status.getStatus())) {
                        lists.add(device);
                    }
                }
            }
        }
        PageInfo<Device> pageInfo = new PageInfo<>(lists);
        int startPage = (pageNum - 1) * pageSize;
        pageInfo.setTotal(lists.size());
        if (startPage == 0) {
            lists = lists.stream().limit(pageSize).collect(Collectors.toList());
        } else {
            lists = lists.stream().skip(startPage).limit(pageSize).collect(Collectors.toList());
        }
        pageInfo.setList(lists);

        return ResultUtil.success(pageInfo);
    }

    @Override
    public Result stopAllByBookMarkId(String bookmarkId) throws Exception {
        StartAndStopRListVo stopRListVo = new StartAndStopRListVo();
        List<StartAllByRBookmarkIdVo> successList = new ArrayList<>();
        List<StartAllByRBookmarkIdVo> errorList = new ArrayList<>();
        List<String> list = this.selectRByBookmarkId(bookmarkId);
        if (list.size() != 0) {
            for (String s : list) {
                Device device = deviceFeignService.getCurrentDevice(s);
                if (device != null) {
                    if ("2".equals(device.getStatus())) {
                        StartAllByRBookmarkIdVo vo = new StartAllByRBookmarkIdVo();
                        String sourceId = device.getLivePeerId();
                        String rid = device.getPeerId();
                        Result<String> stringResult = deviceFeignService.stopLive(rid, sourceId);
                        String errorInfo = stringResult.getErrorInfo();
                        String errorCode = stringResult.getErrorCode();
                        if (stringResult.getErrorCode().equals("0x0")) {
                            vo.setName(device.getName());
                            vo.setPeerId(device.getPeerId());
                            vo.setErrorCode(errorCode);
                            vo.setErrorInfo(errorInfo);
                            successList.add(vo);
                            stopRListVo.setSuccessList(successList);
                        } else {
                            vo.setName(device.getName());
                            vo.setPeerId(device.getPeerId());
                            vo.setErrorCode(errorCode);
                            vo.setErrorInfo(errorInfo);
                            errorList.add(vo);
                            stopRListVo.setErrorList(errorList);
                        }

                    }
                }

            }
        } else {
            return ResultUtil.error("81100101", "Receiver not exist", null);
        }
        return ResultUtil.success(stopRListVo);
    }


    @Override
    public Result getAllChildBookmarkTreeWithDevice(LoginUser user, String bookmarkId, String activeNum) {
        Map<String, String> ownMap = new HashMap<String, String>();
        String bookmarkStr = "[]";
        String parentBookmarkStr = "[]";
        String receiverStr = "[]";
        String livePeerIdStr = "[]";
        String cloudMapStr = "[]";
        try {
            List<VoBookmark> bookmarkList;
            List<VoBookmark> parentBookmarkList = new ArrayList<VoBookmark>();
            List<VoDevice> unBindReceiverList ;
            List<String> livePeerIdList ;
            if (Integer.parseInt(user.getRole()) > 2) {
                // support user do not need bookmark
                if (bookmarkId == null || !StringUtils.isNotBlank(bookmarkId)) {
                    bookmarkId = "0";
                }
                bookmarkList = bookmarkDeviceService.getAllChildBookmarkTreeWithDevice(user, bookmarkId, activeNum);
                //查询bookMark是否被父Id分享
                String parentId = userBookmarkMapper.selectParentId(user.getId());
                if (parentId != null) {
                    parentBookmarkList = bookmarkDeviceService.getBookmarkShareAllChildBookmarkTreeWithDevice(user, bookmarkId, activeNum);
                }
                bookmarkStr = JSONObject.toJSONString(bookmarkList, SerializerFeature.WriteMapNullValue);
                parentBookmarkStr = JSONObject.toJSONString(parentBookmarkList, SerializerFeature.WriteMapNullValue);
                unBindReceiverList = userDeviceService.getUnBindVoReceiverList(user);
                receiverStr = JSONObject.toJSONString(unBindReceiverList, SerializerFeature.WriteMapNullValue);
                //online and live T
             //   livePeerIdList = new ArrayList<String>();
                if (StringUtils.equals("true", activeNum)) {
                    livePeerIdList = userDeviceService.getAllLivePeerIdList(user);
                    Set<String> livePeerIdSet = new HashSet<String>(livePeerIdList);
                    livePeerIdStr = JSONObject.toJSONString(livePeerIdSet, SerializerFeature.WriteMapNullValue);
                }
            }
        } catch (Exception e) {
            log.error("getAllChildBookmarkTreeWithDevice==exception==", e);
            ownMap.put("errorCode", "0x0");
            ownMap.put("bookmark", bookmarkStr);
            ownMap.put("parentBookmark", parentBookmarkStr);
            ownMap.put("receiver", receiverStr);
            ownMap.put("livePeerId", livePeerIdStr);
            ownMap.put("cloudDevice", cloudMapStr);
            ownMap.put("codeUrl", pushLiveUrl + "/home.jsp?pid=");
        }
        if (bookmarkStr != null && receiverStr != null) {
            ownMap.put("errorCode", "0x0");
            ownMap.put("parentBookmark", parentBookmarkStr);
            ownMap.put("bookmark", bookmarkStr);
            ownMap.put("receiver", receiverStr);
            ownMap.put("livePeerId", livePeerIdStr);
            ownMap.put("cloudDevice", cloudMapStr);
            ownMap.put("codeUrl", pushLiveUrl + "/home.jsp?pid=");
        }
        return ResultUtil.success(ownMap);
    }

    @Override
    public List<Device> listReceiverByTimeLockFeature(String userId, SearchDeviceParam param) {
        //1.获取该用户下的Receiver
        param.setReceiver(true);
        List<Device> devices = this.listUserSourceDevices(userId, param);
        if (CollectionUtils.isEmpty(devices)) {
            return new ArrayList<>();
        }
        //2.排除版本小于6.1的设备
        devices = devices.stream().filter(s ->{
            String version = s.getVersion();
            if (StringUtils.isNotEmpty(version)) {
                if (version.length() > 3) {
                    version = version.substring(0, 3);
                }
                return Double.parseDouble(version) >= 6.1;
            }
            return false;
        }).collect(Collectors.toList());
        //3.调用TPC查看有TimeLock Feature的设备
        devices = this.checkTimeLockFeatureFromTpc(userId, devices, LocalConstant.Feature.R_TIMELOCK);
        if (CollectionUtils.isEmpty(devices)) {
            return new ArrayList<>();
        }
        //4.排序
        this.sortDevices(devices, param);
        return devices;
    }

    @Override
    public PageInfo<Device> listPackByTimeLockFeature(String userId, TimeLockPackParam param) {
        //1.获取该用户下所有的Pack
        List<String> tIds = this.listUserCacheTids(userId);
        if (CollectionUtils.isEmpty(tIds)) {
            log.error("listPackByTimeLockFeature>>>>>>> User pack is empty,userId:[{}]",userId);
            return new PageInfo<>();
        }
        //2.获取该R配对的Pack
        Set<String> rids = new HashSet<>();
        rids.add(param.getPeerId());
        Set<String> packIds = this.listRsPairTids(rids);
        if (CollectionUtils.isEmpty(packIds)) {
            log.error("listPackByTimeLockFeature>>>>>>> Receiver pair pack is empty,userId:[{}],rid:[{}]", userId, param.getPeerId());
            return new PageInfo<>();
        }
        packIds = packIds.stream().map(String::toLowerCase).collect(Collectors.toSet());
        tIds.retainAll(packIds);
        //3.获取peerId对应的device
        String peerIds = String.join(",", tIds);
        ListDeviceParam deviceParam = new ListDeviceParam();
        deviceParam.setPeerIds(peerIds);
        List<Device> devices = deviceFeignService.listCurrentDevice(deviceParam);
        if (CollectionUtils.isEmpty(devices)) {
            log.error("listPackByTimeLockFeature>>>>>>> User device is empty,userId:[{}],tIds:[{}]", userId, tIds);
            return new PageInfo<>();
        }
        //4.获取版本大于6.1的Pack
        devices = devices.stream().filter(s->{
            //模糊查询
            String condition = param.getCondition();
            if (StringUtils.isNotEmpty(condition)) {
                if (!StringUtils.containsIgnoreCase(s.getPeerId(), condition) &&
                        !StringUtils.containsIgnoreCase(s.getName(), condition)) {
                    return false;
                }
            }
            String version = s.getVersion();
            if (StringUtils.isNotEmpty(version)) {
                if (version.length() > 3) {
                    version = version.substring(0, 3);
                }
                return Double.parseDouble(version) >= 6.1;
            }
            return false;
        }).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(devices)) {
            log.error("listPackByTimeLockFeature>>>>>>> filter device is empty,userId:[{}],tIds:[{}]", userId, tIds);
            return new PageInfo<>();
        }
        //5.去TPC中校验设备是否含有TimeLock的Feature
        devices = this.checkTimeLockFeatureFromTpc(userId, devices, LocalConstant.Feature.T_TIMELOCK);
        if (CollectionUtils.isEmpty(devices)) {
            log.error("listPackByTimeLockFeature>>>>>>> Device TimeLock Feature is empty,userId:[{}],tIds:[{}]", userId, tIds);
            return new PageInfo<>();
        }
        //6.排序/分页
        devices.sort(Comparator.comparing(Device::getStatus).reversed());
        int pageNum = param.getPageNum();
        int pageSize = param.getPageSize();
        int startIndex = (pageNum - 1) * pageSize;
        List<Device> collect = startIndex <= 0 ? devices.stream().limit(pageSize).collect(Collectors.toList())
                : devices.stream().skip(startIndex).limit(pageSize).collect(Collectors.toList());
        PageInfo<Device> devicePageInfo = new PageInfo<>(collect);
        devicePageInfo.setPageNum(pageNum);
        devicePageInfo.setPageSize(pageSize);
        devicePageInfo.setTotal(devices.size());
        devicePageInfo.setPages(devices.size());
        devicePageInfo.setList(collect);
        return devicePageInfo;
    }

    @Override
    public boolean checkSourceIsOwnerByUserId(String userId, String peerId) {
        UserDevice record = new UserDevice()
                .setUserId(userId)
                .setPeerId(peerId);
        List<UserDevice> existList = userDeviceMapper.select(record);
        if (CollectionUtils.isEmpty(existList)) {
            return false;
        }
        existList = existList.stream().filter(s -> s.getRelation() != null && s.getRelation() == 1).collect(Collectors.toList());
        return !CollectionUtils.isEmpty(existList);
    }

    @Override
    public List<String> listExtByUserId(String userId,String condition) {
        String types = UserUtil.packageExtTypesToString(extType);
        condition = MyUtil.formatCondition(condition);
        return userDeviceMapper.listUserExt(userId, condition, types);
    }

    /**
     * 过滤掉没有timeLock的Receiver
     * @param userId 用户id
     * @param devices 所有的device
     * @param featureName 指定feature
     * @return 返回的device
     */
    private List<Device> checkTimeLockFeatureFromTpc(String userId, List<Device> devices,String featureName) {
        try {
            List<String> allPeerIds = devices.stream().map(Device::getPeerId).collect(Collectors.toList());
            Result<List<String>> existPeerIdResult = userHttpService.getTpcFeatureEnable(new GetTpcFeatureEnableParam(featureName, allPeerIds));
            if (existPeerIdResult == null || !existPeerIdResult.assertSuccess()) {
                log.error("listReceiverByTimeLockFeature>>>>>> call TPC failed.userId:[{}],peerIds:[{}],result:[{}]",
                        userId, allPeerIds, existPeerIdResult);
                throw new ServerException(ResultConstant.TPC.REQUEST_FAILED);
            }
            List<String> existPeerIds = existPeerIdResult.getResult();
            if (CollectionUtils.isEmpty(existPeerIds)) {
                log.error("listReceiverByTimeLockFeature>>>>>> TmeLockReceiver result is empty.userId:[{}],peerIds:[{}],result:[{}]",
                        userId, allPeerIds, existPeerIdResult);
                return new ArrayList<>();
            }
            List<String> existLowerPeerIds = existPeerIds.stream().map(String::toLowerCase).collect(Collectors.toList());
            devices = devices.stream().filter(s -> existLowerPeerIds.contains(s.getPeerId()))
                    .collect(Collectors.toList());
        } catch (Exception e) {
            log.error("listReceiverByTimeLockFeature>>>>>> call TPC exception.userId:[{}],exception:[{}]", userId, e);
            throw new ServerException(ResultConstant.TPC.REQUEST_EXCEPTION);
        }
        return devices;
    }


    @Override
    public List<String> listOwnerGridId(String userId, String condition) {
        return userDeviceMapper.listOwnerXIds(userId, condition);
    }

    @Override
    public List<String> listOwnerXAndPackId(String userId, String condition) {
        return userDeviceMapper.listOwnerXAndPackId(userId, condition);
    }

    @Override
    public List<String> listOwnerPackId(String userId, String condition) {
        return userDeviceMapper.listOwnerPackId(userId, condition);
    }

    @Override
    public List<String> pageOwnerAnywhere(String userId, String condition, String rid) {
        if (!StringUtils.isEmpty(rid)) {
            List<String> list = new ArrayList<>();
            list.add(rid);
            List<String> anyWhere = new ArrayList<>();
            List<AnyWhereVo> tokenAnywhereOwner = tokenFeignService.listParamRsPairedTids(list);
            for (AnyWhereVo anyWhereVo : tokenAnywhereOwner) {
                Boolean ownerDeviceById = tokenFeignService.isOwnerDeviceById(anyWhereVo.getId());
                if (ownerDeviceById){
                    if(!StringUtils.isEmpty(anyWhereVo.getPeerId())){
                        anyWhere.add(anyWhereVo.getPeerId());
                    }
                }
            }
            List<Device> deviceList = deviceService.listCurrentDevice(anyWhere);
            if(CollectionUtils.isEmpty(deviceList)){
                return  new ArrayList<>();
            }
            List<Device> collect = deviceList.stream().filter(s ->
                    StringUtils.containsIgnoreCase(s.getPeerId(), condition)
                            || StringUtils.containsIgnoreCase(s.getName(), condition)).collect(Collectors.toList());
            List<String> anyWhereList = collect.stream().map(Device::getPeerId).collect(Collectors.toList());
            return   anyWhereList;
        }
        return  new ArrayList<>();
    }

    @Override
    public Result bingUserAndReceiver(String userId, String rid) {
        log.error("bingUserAndReceiver>>>>>>> userId:[{}],rid:[{}]", userId, rid);
        List<String> list = new ArrayList<>();
        list.add(rid);
        //获取R衍生的Grid
        Map<String, List<Device>> stringListMap = deviceFeignService.listReceiversGrid(list);
        List<Device> gridList = stringListMap.get(rid);
        gridList.forEach(s->{
            if (StringUtils.isNotEmpty(s.getPeerId())){
                list.add(s.getPeerId());
            }
        });
        this.correlateUserDevice(userId, String.join(",", list.stream().map(String::valueOf).collect(Collectors.joining(","))), null, null, null, userId, true);
        return ResultUtil.success();
    }

    @Override
    public Result deleteUserAndReceiver(String userId, String rid) {
        log.error("bingUserAndReceiver>>>>>>> userId:[{}],rid:[{}]", userId, rid);
        List<String> list = new ArrayList<>();
        list.add(rid);
        //获取R衍生的Grid
        Map<String, List<Device>> stringListMap = deviceFeignService.listReceiversGrid(list);
        List<Device> gridList = stringListMap.get(rid);
        gridList.forEach(s->{
            if (StringUtils.isNotEmpty(s.getPeerId())){
                list.add(s.getPeerId());
            }
        });
        this.correlateUserDevice(userId,null, String.join(",", list.stream().map(String::valueOf).collect(Collectors.joining(","))), null, null, userId, true);
        return ResultUtil.success();
    }

    @Override
    public Map<String, List<UserDevice>> listUserDeviceOfDirtyData() {
        Map<String, List<UserDevice>> result = new HashMap<>();
        Map<String, Integer> integerMap = new HashMap<>();
        integerMap.put("count", 0);
        long startTime = System.currentTimeMillis();
        //1.获取所有拥有子账号的用户信息
        List<User> users = userService.getUserOfAdminAndHaveSonUser();
        if (CollectionUtils.isEmpty(users)) {
            log.error("listUserDeviceOfDirtyData>>>>>>> not adminAccount");
            return new HashMap<>();
        }
        log.error("listUserDeviceOfDirtyData>>>>>userIdSize,size:[{}]", users.size());
        users.forEach(user -> {
            //获取该用户下所有的source
            String userId = user.getId();
            String email = user.getEmail();
            //这是用户下的 tvu_user_device表里的设备
            List<String> peerIds = userDeviceMapper.getDeviceByUserId(userId);
            // tvu_token_pair表里的设备属于和R进行配对的,也属于用户
            if(!CollectionUtils.isEmpty(peerIds)){
                List<String> tokenpeerIds= tokenRequestMapper.getDeviceByPeerIds(peerIds);
                peerIds.addAll(tokenpeerIds);
            }
            List<String> adminPeerIds = CollectionUtils.isEmpty(peerIds) ? new ArrayList<>() : peerIds.stream().map(String::toLowerCase).collect(Collectors.toList());
            log.error("listUserDeviceOfDirtyData1111>>>>>userId:[{}],adminPeerId:[{}],email:[{}]", userId, adminPeerIds, email);
            //2.获取用户下所有的sonUser
            List<String> sonUserIds = userService.listSonUserIds(userId);
            if (CollectionUtils.isEmpty(sonUserIds)) {
                log.error("listUserDeviceOfDirtyData222222>>>>>sonUser is empty,userId:[{}],email:[{}]", userId, email);
                return;
            }
            sonUserIds.forEach(sonUserId ->{
                //获取sonUser下的source
                List<String> sonPeerIds = userDeviceMapper.getDeviceByUserId(sonUserId);
                if (CollectionUtils.isEmpty(sonPeerIds)) {
                    log.error("listUserDeviceOfDirtyData3333333>>>>>sonUser is not device,userId:[{}],email:[{}],sonUserId:[{}]", userId, email, sonUserId);
                    return;
                }
                sonPeerIds = sonPeerIds.stream().map(String::toLowerCase).collect(Collectors.toList());
                sonPeerIds.removeAll(adminPeerIds);
                if (CollectionUtils.isEmpty(sonPeerIds)) {
                    log.error("listUserDeviceOfDirtyData44444>>>>>sonDevice the same of adminDevice,userId:[{}],email:[{}],sonUserId:[{}]", userId, email, sonUserId);
                    return;
                }
                List<UserDevice> userDevices = userDeviceMapper.listByUserIdAndPeerIds(sonUserId, sonPeerIds);
                Integer count = integerMap.get("count");
                integerMap.put("count", count + userDevices.size());
                result.put(userId + "[" + email + "]-" + sonUserId, userDevices);
            });
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                log.error("listUserDeviceOfDirtyData888888>>>>>>>sleep exception", e);
            }

        });
        long speedTime = System.currentTimeMillis() - startTime;
        log.error("listUserDeviceOfDirtyData9999>>>>integerMap:[{}],result:[{}],speedTime:[{}]", integerMap.get("count"), result, speedTime);
        return result;
    }

    @Override
    public List<UserDevice> deleteDirtyData(String userId, int index) {
        User user = userService.getById(userId);
        if (user == null) {
            throw new ServerException(ResultConstant.User.USER_NOT_EXIST);
        }
        List<UserDevice> result = new ArrayList<>();
        log.error("deleteDirtyData>>>>>userId:[{}],user:[{}]", userId, user);
        Map<String, List<UserDevice>> stringMapMap = this.listUserDeviceOfDirtyData();

        if (!CollectionUtils.isEmpty(stringMapMap)) {
            for (Map.Entry<String, List<UserDevice>> stringMapEntry : stringMapMap.entrySet()) {
                index--;
                List<UserDevice> userDevices = stringMapEntry.getValue();
                log.error("deleteDirtyData1111>>>>>>>>deleteBefore, userDevices:[{}]", userDevices);
                List<String> collect = userDevices.stream().map(UserDevice::getId).collect(Collectors.toList());
                log.error("deleteDirtyData1111>>>>>>>>deleteBefore, userDeviceIds:[{}]", collect);
                if (!CollectionUtils.isEmpty(collect)) {
                    int i = userDeviceMapper.deleteByIdList(collect);
                    log.error("deleteDirtyData1111>>>>>>>>deleteAfter,count:[{}]", i);
                }
                result.addAll(userDevices);
                if (index <= 0 ) {
                    log.error("deleteDirtyData>>>>>>>>>deleted userDevice is index:[{}] result:[{}]", index, result);
                    return result;
                }
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    log.error("deleteDirtyData8888>>>>>>sleep exception", e);
                }

            }
        }
        log.error("deleteDirtyData>>>>>>>>>deleted userDevice is result:[{}]", result);
        return result;
    }


    @Override
    public List<UserDevice> deviceDeleteByEmail(String email) {
        //判断该账号是User还是Admin
        User user = userService.getByEmail(email);
        if (LocalConstant.UserRole.ADMIN.equals(user.getRole())) {
            log.error("email   is---> email:[{}],userId:[{}]", email,user.getId());
            //查询admin的全部子账号
            List<String> sonUserIds = userMapper.listSonUserIds(user.getId());
            //查询admin下的设备
            List<String> deviceByAdmin = userDeviceMapper.getDeviceByUserId(user.getId());
            // tvu_token_pair表里的设备属于和R进行配对的,也属于用户
            if(!CollectionUtils.isEmpty(deviceByAdmin)){
                List<String> tokenpeerIds= tokenRequestMapper.getDeviceByPeerIds(deviceByAdmin);
                deviceByAdmin.addAll(tokenpeerIds);
            }
            List<UserDevice> returnList = new ArrayList<>();
            for (String sonUserId : sonUserIds) {
                log.error("sonUserId   is---> userId:[{}],email:[{}]", sonUserId,userService.getById(sonUserId).getEmail());
                //查询全部的子账号下的Device
                List<String> deviceByUserId = userDeviceMapper.getDeviceByUserId(sonUserId);
                //一一匹配,如果子账号的设备多余admin账号的设备,那么认为多余的是脏数据.
                deviceByUserId.removeAll(deviceByAdmin);
                if (CollectionUtils.isEmpty(deviceByUserId)) {
                    log.error("listUserDeviceOfEthan6666 deviceByUserId is>>>>>null ");
                    continue;
                }
                List<UserDevice> userDevices = userDeviceMapper.listByUserIdAndPeerIds(sonUserId, deviceByUserId);
                returnList.addAll(userDevices);
                List<String> collect = userDevices.stream().map(UserDevice::getId).collect(Collectors.toList());
                if (!CollectionUtils.isEmpty(collect)) {
                    int i = userDeviceMapper.deleteByIdList(collect);
                    log.error("deleteDirtyHistory11111>>>>>>>>deleteAfter,count:[{}]", i);
                }
            }
            log.error("deleteDirtyDataEthanAdmin>>>>>>>>deleteBefore, returnList:[{}]", returnList);
            return returnList;
        }

        if (LocalConstant.UserRole.USER.equals(user.getRole())) {
            log.error("delete user email   is---> email:[{}], userId:[{}]", email,user.getId());
            //如果是user级别账号
            String parentId = user.getUserParentId();
            //查出父账号全部的设备
            List<String> peerIds = userDeviceMapper.getDeviceByUserId(parentId);
            // tvu_token_pair表里的设备属于和R进行配对的,也属于用户
            if(!CollectionUtils.isEmpty(peerIds)){
                List<String> tokenpeerIds= tokenRequestMapper.getDeviceByPeerIds(peerIds);
                peerIds.addAll(tokenpeerIds);
            }
            List<String> deviceByUserId = userDeviceMapper.getDeviceByUserId(user.getId());
            //一一匹配,如果子账号的设备多余admin账号的设备,那么认为多余的是脏数据.
            deviceByUserId.removeAll(peerIds);
            if (CollectionUtils.isEmpty(deviceByUserId)) {
                log.error("listUserDeviceOfEthan44444  deviceByUserId is>>>>>null ");
                return null;
            }
            List<UserDevice> userDevices = userDeviceMapper.listByUserIdAndPeerIds(user.getId(), deviceByUserId);
            List<String> collect = userDevices.stream().map(UserDevice::getId).collect(Collectors.toList());
            log.error("deleteDirtyDataEthan999>>>>>>>>deleteBefore, userDeviceIds:[{}]", collect);
            if (!CollectionUtils.isEmpty(collect)) {
                int i = userDeviceMapper.deleteByIdList(collect);
                log.error("deleteDirtyEthan11111>>>>>>>>deleteAfter,count:[{}]", i);
            }
            log.error("deleteDirtyDataEthan>>>>>>>>deleteBefore, userDevice:[{}]", userDevices);
            return userDevices ;
        }

        return null;
    }


    @Override
    public Result<String> setGridByUserId(String userId, String gridId) {
        User user = userService.getById(userId);
        if(user==null) {
            throw new ServerException(ResultConstant.User.USER_NOT_EXIST);
        }
        Device dbDevice = deviceFeignService.getDBDevice(gridId);
        if(dbDevice==null){
             throw new ServerException(ResultConstant.GridEvent.GRID_NOT_EXIST);
        }
        boolean userOwnDevice = userDeviceService.isUserOwnDevice(userId, gridId);
        if(userOwnDevice){
            throw new ServerException(ResultConstant.UserDevice.USER_HAVA_DEVICE);
        }
        userDeviceService.addUserDevice(userId,gridId);
        return ResultUtil.success();
    }

    @Override
    public void correlateAnywhere(AnywhereParam param, LoginUser loginUser) {
        String userId = param.getUserId();
        List<Anywhere> addAnyWhere = param.getAddAnyWhere();
        List<Anywhere> removeAnyWhere = param.getRemoveAnyWhere();
        if (!CollectionUtils.isEmpty(addAnyWhere)) {
            for (Anywhere anywhere : addAnyWhere) {
                if (StringUtils.isEmpty(anywhere.getId())) {
                    //如果id等于null,那肯定不是tvu_token_device表的数据,因为tvu_token_device数据在回显时已经将主键id回显
                    //表示授权
                    this.correlateUserDevice(userId, null, null, anywhere.getPeerId(), null, loginUser.getId());
                } else {
                    //根据Id去 tvu_token_device表中查询,查看是否为token表中数据
                    Boolean deviceById = tokenFeignService.getDeviceById(anywhere.getId());
                    if (!deviceById) {
                        //那么认为是tvu_user_device表中数据
                        //表示授权
                        this.correlateUserDevice(userId, null, null, anywhere.getPeerId(), null, loginUser.getId());
                    } else {
                        //更新tvu_token_device表中授权属性
                        tokenFeignService.updateDeviceById(anywhere.getId(), 1);
                    }
                }
            }
        }
        if (!CollectionUtils.isEmpty(removeAnyWhere)) {
            for (Anywhere anywhere : removeAnyWhere) {
                if (StringUtils.isEmpty(anywhere.getId())) {
                    //如果id等于null,那肯定不是tvu_token_device表的数据,因为tvu_token_device数据在回显时已经将主键id回显
                    //表示授权
                    this.correlateUserDevice(userId, null, null, null, anywhere.getPeerId(), loginUser.getId());
                } else {
                    //根据Id去 tvu_token_device表中查询,查看是否为token表中数据
                    Boolean deviceById = tokenFeignService.getDeviceById(anywhere.getId());
                    if (!deviceById) {
                        //那么认为是tvu_user_device表中数据
                        //表示取消授权
                        this.correlateUserDevice(userId, null, null, null, anywhere.getPeerId(), loginUser.getId());
                    } else {
                        //更新tvu_token_device表中授权属性
                        tokenFeignService.updateDeviceById(anywhere.getId(), 0);
                    }
                }
            }
        }
    }


    @Override
    public Result isUserOwnerByListPeerId(LoginUser loginUser,OwnerByListPeerIdParam param) {
        boolean result = true;
        List<String> peerIdList = param.getPackList();
        List<String> anyWhereList = param.getAnyWhereList();
        String userRole = loginUser.getRole();
        if (LocalConstant.UserRole.ADMIN.equals(userRole) || LocalConstant.UserRole.USER.equals(userRole)) {
            List<OwnerPeerIdVo> list = new ArrayList<>();
            if (!CollectionUtils.isEmpty(peerIdList)) {
                for (String peerId : peerIdList) {
                    OwnerPeerIdVo owner = new OwnerPeerIdVo();
                    result = userDeviceService.isUserOwner(loginUser.getId(), peerId);
                    owner.setCreatEvent(result);
                    owner.setPeerId(peerId);
                    list.add(owner);
                }
            }

            //查询Anywhere的owner权限
            if (!CollectionUtils.isEmpty(anyWhereList)) {
                for (String peerId : anyWhereList) {
                    OwnerPeerIdVo ownerAnywhere = new OwnerPeerIdVo();
                    Boolean owner = tokenFeignService.ownerDeviceByUserIdAndPeerId(loginUser.getId(), peerId);
                    if (owner) {
                        ownerAnywhere.setCreatEvent(owner);
                        ownerAnywhere.setPeerId(peerId);
                    } else {
                        result = userDeviceService.isUserOwner(loginUser.getId(), peerId);
                        if (result) {
                            ownerAnywhere.setCreatEvent(result);
                        }
                        ownerAnywhere.setPeerId(peerId);
                    }
                    list.add(ownerAnywhere);
                }
            }

            return ResultUtil.success(list);
        }
        return ResultUtil.success();
    }
}
